GDScript: Anonymous lambda names include name of variable assigned to

This commit is contained in:
rune-scape 2024-10-15 21:53:24 -07:00 committed by rune-scape
parent 9006086fa6
commit 6757f27dec
3 changed files with 35 additions and 5 deletions

View file

@ -2258,6 +2258,9 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
if (p_func) { if (p_func) {
if (p_func->identifier) { if (p_func->identifier) {
func_name = p_func->identifier->name; func_name = p_func->identifier->name;
} else if (p_func->source_lambda && p_func->source_lambda->parent_variable) {
GDScriptParser::AssignableNode *parent_variable = p_func->source_lambda->parent_variable;
func_name = vformat("<anonymous lambda(%s)>", parent_variable->identifier->name);
} else { } else {
func_name = "<anonymous lambda>"; func_name = "<anonymous lambda>";
} }

View file

@ -812,9 +812,8 @@ bool GDScriptParser::has_class(const GDScriptParser::ClassNode *p_class) const {
GDScriptParser::ClassNode *GDScriptParser::parse_class(bool p_is_static) { GDScriptParser::ClassNode *GDScriptParser::parse_class(bool p_is_static) {
ClassNode *n_class = alloc_node<ClassNode>(); ClassNode *n_class = alloc_node<ClassNode>();
ClassNode *previous_class = current_class; n_class->outer = current_class;
current_class = n_class; ScopedSet scoped_set_current_class(current_class, n_class);
n_class->outer = previous_class;
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for the class name after "class".)")) { if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for the class name after "class".)")) {
n_class->identifier = parse_identifier(); n_class->identifier = parse_identifier();
@ -838,7 +837,6 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class(bool p_is_static) {
bool multiline = match(GDScriptTokenizer::Token::NEWLINE); bool multiline = match(GDScriptTokenizer::Token::NEWLINE);
if (multiline && !consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) { if (multiline && !consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) {
current_class = previous_class;
complete_extents(n_class); complete_extents(n_class);
return n_class; return n_class;
} }
@ -858,7 +856,6 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class(bool p_is_static) {
consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)"); consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)");
} }
current_class = previous_class;
return n_class; return n_class;
} }
@ -981,6 +978,8 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(b
} }
void GDScriptParser::parse_class_body(bool p_is_multiline) { void GDScriptParser::parse_class_body(bool p_is_multiline) {
ScopedSet scoped_set_current_variable(current_variable, nullptr);
bool class_end = false; bool class_end = false;
bool next_is_static = false; bool next_is_static = false;
while (!class_end && !is_at_end()) { while (!class_end && !is_at_end()) {
@ -1079,6 +1078,8 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_is_static) {
GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_is_static, bool p_allow_property) { GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_is_static, bool p_allow_property) {
VariableNode *variable = alloc_node<VariableNode>(); VariableNode *variable = alloc_node<VariableNode>();
ScopedSet scoped_set_current_variable(current_variable, variable);
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected variable name after "var".)")) { if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected variable name after "var".)")) {
complete_extents(variable); complete_extents(variable);
return nullptr; return nullptr;
@ -1315,6 +1316,8 @@ void GDScriptParser::parse_property_getter(VariableNode *p_variable) {
GDScriptParser::ConstantNode *GDScriptParser::parse_constant(bool p_is_static) { GDScriptParser::ConstantNode *GDScriptParser::parse_constant(bool p_is_static) {
ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode *constant = alloc_node<ConstantNode>();
ScopedSet scoped_set_current_variable(current_variable, constant);
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) { if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) {
complete_extents(constant); complete_extents(constant);
return nullptr; return nullptr;
@ -1358,6 +1361,9 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() {
} }
ParameterNode *parameter = alloc_node<ParameterNode>(); ParameterNode *parameter = alloc_node<ParameterNode>();
ScopedSet scoped_set_current_variable(current_variable, parameter);
parameter->identifier = parse_identifier(); parameter->identifier = parse_identifier();
if (match(GDScriptTokenizer::Token::COLON)) { if (match(GDScriptTokenizer::Token::COLON)) {
@ -1705,6 +1711,8 @@ bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_ta
} }
GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite, bool p_for_lambda) { GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite, bool p_for_lambda) {
ScopedSet scoped_set_current_variable(current_variable, nullptr);
SuiteNode *suite = p_suite != nullptr ? p_suite : alloc_node<SuiteNode>(); SuiteNode *suite = p_suite != nullptr ? p_suite : alloc_node<SuiteNode>();
suite->parent_block = current_suite; suite->parent_block = current_suite;
suite->parent_function = current_function; suite->parent_function = current_function;
@ -3410,6 +3418,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
LambdaNode *lambda = alloc_node<LambdaNode>(); LambdaNode *lambda = alloc_node<LambdaNode>();
lambda->parent_function = current_function; lambda->parent_function = current_function;
lambda->parent_lambda = current_lambda; lambda->parent_lambda = current_lambda;
lambda->parent_variable = current_variable;
FunctionNode *function = alloc_node<FunctionNode>(); FunctionNode *function = alloc_node<FunctionNode>();
function->source_lambda = lambda; function->source_lambda = lambda;

View file

@ -931,6 +931,7 @@ public:
FunctionNode *function = nullptr; FunctionNode *function = nullptr;
FunctionNode *parent_function = nullptr; FunctionNode *parent_function = nullptr;
LambdaNode *parent_lambda = nullptr; LambdaNode *parent_lambda = nullptr;
AssignableNode *parent_variable = nullptr;
Vector<IdentifierNode *> captures; Vector<IdentifierNode *> captures;
HashMap<StringName, int> captures_indices; HashMap<StringName, int> captures_indices;
bool use_self = false; bool use_self = false;
@ -1325,6 +1326,22 @@ public:
}; };
private: private:
template <typename T>
class ScopedSet {
T *var;
T old_value;
public:
template <typename TNew>
ScopedSet(T &p_var, const TNew &p_new_value) :
var(&p_var), old_value(p_var) {
p_var = p_new_value;
}
~ScopedSet() {
*var = old_value;
}
};
friend class GDScriptAnalyzer; friend class GDScriptAnalyzer;
friend class GDScriptParserRef; friend class GDScriptParserRef;
@ -1365,6 +1382,7 @@ private:
FunctionNode *current_function = nullptr; FunctionNode *current_function = nullptr;
LambdaNode *current_lambda = nullptr; LambdaNode *current_lambda = nullptr;
SuiteNode *current_suite = nullptr; SuiteNode *current_suite = nullptr;
AssignableNode *current_variable = nullptr;
CompletionContext completion_context; CompletionContext completion_context;
CompletionCall completion_call; CompletionCall completion_call;