Fix string interpolation autocomplete

This commit is contained in:
Kampfkarren 2022-11-15 13:12:39 -08:00
parent c32cdd5c42
commit eb53fa5bec
5 changed files with 36 additions and 37 deletions

View file

@ -1,6 +1,7 @@
// 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/Ast.h"
#include "Luau/Module.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"

View file

@ -1227,11 +1227,8 @@ static bool stringPartOfInterpString(const AstNode* node, Position position)
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;
@ -1239,7 +1236,6 @@ static bool stringPartOfInterpString(const AstNode* node, Position position)
}
return true;
// return node->is<AstExprInterpString>();
}
static std::optional<AutocompleteEntryMap> autocompleteStringParams(const SourceModule& sourceModule, const ModulePtr& module,

View file

@ -22,7 +22,7 @@ bool lua_telemetry_parsed_named_non_function_type = false;
LUAU_FASTFLAGVARIABLE(LuauErrorDoubleHexPrefix, false)
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
LUAU_FASTFLAGVARIABLE(LuauInterpolatedStringBaseSupport, false)
LUAU_FASTFLAGVARIABLE(LuauInterpolatedStringBaseSupport, true)
LUAU_FASTFLAGVARIABLE(LuauCommaParenWarnings, false)
LUAU_FASTFLAGVARIABLE(LuauTableConstructorRecovery, false)
@ -2661,6 +2661,7 @@ AstExpr* Parser::parseInterpString()
TempVector<AstExpr*> expressions(scratchExpr);
Location startLocation = lexer.current().location;
Location endLocation;
do
{
@ -2668,17 +2669,16 @@ AstExpr* Parser::parseInterpString()
LUAU_ASSERT(currentLexeme.type == Lexeme::InterpStringBegin || currentLexeme.type == Lexeme::InterpStringMid ||
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);
if (!Lexer::fixupQuotedString(scratchData))
{
nextLexeme();
printf("FIXUP QUOTED STRING FAIL\n");
return reportExprError(startLocation, {}, "Interpolated string literal contains malformed escape sequence");
return reportExprError(Location{startLocation, endLocation}, {}, "Interpolated string literal contains malformed escape sequence");
}
AstArray<char> chars = copy(scratchData);
@ -2689,10 +2689,7 @@ AstExpr* Parser::parseInterpString()
if (currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple)
{
AstArray<AstArray<char>> stringsArray = copy(strings);
AstArray<AstExpr*> expressionsArray = copy(expressions);
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
break;
}
switch (lexer.current().type)
@ -2701,20 +2698,14 @@ AstExpr* Parser::parseInterpString()
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);
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, expected expression inside '{}'"));
break;
}
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);
expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, did you forget to add a '`'?"));
break;
}
default:
expressions.push_back(parseExpr());
@ -2728,17 +2719,18 @@ AstExpr* Parser::parseInterpString()
break;
case Lexeme::BrokenInterpDoubleBrace:
nextLexeme();
printf("BROKEN INTERP DOUBLE BRACE\n");
return reportExprError(location, {}, ERROR_INVALID_INTERP_DOUBLE_BRACE);
return reportExprError(endLocation, {}, 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 '}'?");
return reportExprError(endLocation, {}, "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());
return reportExprError(endLocation, {}, "Malformed interpolated string, got %s", lexer.current().toString().c_str());
}
} 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()

View file

@ -183,7 +183,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprInterpString")
AstStat* statement = expectParseStatement("local a = `var = {x}`");
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);
}

View file

@ -2712,15 +2712,24 @@ a = if temp then even else abc@3
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(`@1`))");
auto ac = autocomplete('1');
CHECK(ac.entryMap.empty());
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`))");
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_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_EQ(ac.context, AutocompleteContext::Expression);
check(R"(f(`expression = {@1--[[ bla bla bla ]]`))");
check(R"(f(`expression = {@1 --[[ bla bla bla ]]`))");
ac = autocomplete('1');
CHECK(!ac.entryMap.empty());
CHECK(ac.entryMap.count("table"));
CHECK_EQ(ac.context, AutocompleteContext::Expression);
}