You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Merge pull request #102218 from HolonProduction/dictionary-recovery
GDScript: Do phrase level recovery when parsing faulty dictionaries
This commit is contained in:
@@ -3122,13 +3122,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
|
|||||||
case DictionaryNode::LUA_TABLE:
|
case DictionaryNode::LUA_TABLE:
|
||||||
if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) {
|
if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) {
|
||||||
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
|
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
|
||||||
advance();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) {
|
if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) {
|
||||||
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
|
push_error(R"(Expected identifier or string as Lua-style dictionary key (e.g "{ key = value }").)");
|
||||||
advance();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!match(GDScriptTokenizer::Token::EQUAL)) {
|
if (!match(GDScriptTokenizer::Token::EQUAL)) {
|
||||||
if (match(GDScriptTokenizer::Token::COLON)) {
|
if (match(GDScriptTokenizer::Token::COLON)) {
|
||||||
@@ -3168,6 +3164,21 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
|
|||||||
if (key != nullptr && value != nullptr) {
|
if (key != nullptr && value != nullptr) {
|
||||||
dictionary->elements.push_back({ key, value });
|
dictionary->elements.push_back({ key, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do phrase level recovery by inserting an imaginary expression for missing keys or values.
|
||||||
|
// This ensures the successfully parsed expression is part of the AST and can be analyzed.
|
||||||
|
if (key != nullptr && value == nullptr) {
|
||||||
|
LiteralNode *dummy = alloc_recovery_node<LiteralNode>();
|
||||||
|
dummy->value = Variant();
|
||||||
|
|
||||||
|
dictionary->elements.push_back({ key, dummy });
|
||||||
|
} else if (key == nullptr && value != nullptr) {
|
||||||
|
LiteralNode *dummy = alloc_recovery_node<LiteralNode>();
|
||||||
|
dummy->value = Variant();
|
||||||
|
|
||||||
|
dictionary->elements.push_back({ dummy, value });
|
||||||
|
}
|
||||||
|
|
||||||
} while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
|
} while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
|
||||||
}
|
}
|
||||||
pop_multiline();
|
pop_multiline();
|
||||||
|
|||||||
@@ -1451,6 +1451,18 @@ private:
|
|||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocates a node for patching up the parse tree when an error occurred.
|
||||||
|
// Such nodes don't track their extents as they don't relate to actual tokens.
|
||||||
|
template <typename T>
|
||||||
|
T *alloc_recovery_node() {
|
||||||
|
T *node = memnew(T);
|
||||||
|
node->next = list;
|
||||||
|
list = node;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void push_error(const String &p_message, const Node *p_origin = nullptr);
|
void push_error(const String &p_message, const Node *p_origin = nullptr);
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
exclude=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
t = 1,
|
||||||
|
AutoTranslateMode.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
exclude=[
|
||||||
|
{"display": "VALUE"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
t = 1,
|
||||||
|
TestEnum.➡ = 1,
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
t = AutoTranslateMode.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "VALUE"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
= TestEnum.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
t = 1,
|
||||||
|
e AutoTranslateMode.➡,
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "VALUE"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
1 = TestEnum.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
t = 1,
|
||||||
|
1 AutoTranslateMode.➡,
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
AutoTranslateMode.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
AutoTranslateMode.➡:
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "VALUE"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
TestEnum.➡ "test"
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
AutoTranslateMode.➡: 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
1: AutoTranslateMode.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "VALUE"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
: TestEnum.➡
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
{"display": "AUTO_TRANSLATE_MODE_INHERIT"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var test = {
|
||||||
|
1 AutoTranslateMode.➡
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user