Skip to content

Commit bef5d1e

Browse files
committed
Merge pull request godotengine#102218 from HolonProduction/dictionary-recovery
GDScript: Do phrase level recovery when parsing faulty dictionaries
2 parents 6989a08 + ca1e444 commit bef5d1e

30 files changed

+177
-4
lines changed

modules/gdscript/gdscript_parser.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3122,13 +3122,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
31223122
case DictionaryNode::LUA_TABLE:
31233123
if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) {
31243124
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
3125-
advance();
3126-
break;
31273125
}
31283126
if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) {
31293127
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
3130-
advance();
3131-
break;
31323128
}
31333129
if (!match(GDScriptTokenizer::Token::EQUAL)) {
31343130
if (match(GDScriptTokenizer::Token::COLON)) {
@@ -3168,6 +3164,21 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
31683164
if (key != nullptr && value != nullptr) {
31693165
dictionary->elements.push_back({ key, value });
31703166
}
3167+
3168+
// Do phrase level recovery by inserting an imaginary expression for missing keys or values.
3169+
// This ensures the successfully parsed expression is part of the AST and can be analyzed.
3170+
if (key != nullptr && value == nullptr) {
3171+
LiteralNode *dummy = alloc_recovery_node<LiteralNode>();
3172+
dummy->value = Variant();
3173+
3174+
dictionary->elements.push_back({ key, dummy });
3175+
} else if (key == nullptr && value != nullptr) {
3176+
LiteralNode *dummy = alloc_recovery_node<LiteralNode>();
3177+
dummy->value = Variant();
3178+
3179+
dictionary->elements.push_back({ dummy, value });
3180+
}
3181+
31713182
} while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
31723183
}
31733184
pop_multiline();

modules/gdscript/gdscript_parser.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,18 @@ class GDScriptParser {
14511451

14521452
return node;
14531453
}
1454+
1455+
// Allocates a node for patching up the parse tree when an error occurred.
1456+
// Such nodes don't track their extents as they don't relate to actual tokens.
1457+
template <typename T>
1458+
T *alloc_recovery_node() {
1459+
T *node = memnew(T);
1460+
node->next = list;
1461+
list = node;
1462+
1463+
return node;
1464+
}
1465+
14541466
void clear();
14551467
void push_error(const String &p_message, const Node *p_origin = nullptr);
14561468
#ifdef DEBUG_ENABLED
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[output]
2+
exclude=[
3+
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
4+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extends Node
2+
3+
var test = {
4+
t = 1,
5+
AutoTranslateMode.➡
6+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[output]
2+
exclude=[
3+
{"display": "VALUE"},
4+
]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
extends Node
2+
3+
enum TestEnum {
4+
VALUE,
5+
}
6+
7+
var test = {
8+
t = 1,
9+
TestEnum.➡ = 1,
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[output]
2+
include=[
3+
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
4+
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extends Node
2+
3+
var test = {
4+
t = AutoTranslateMode.➡
5+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[output]
2+
include=[
3+
{"display": "VALUE"},
4+
]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extends Node
2+
3+
enum TestEnum {
4+
VALUE,
5+
}
6+
7+
var test = {
8+
= TestEnum.➡
9+
}

0 commit comments

Comments
 (0)