Procházet zdrojové kódy

GDScript: Fix and improve annotation parsing

Danil Alexeev před 2 roky
rodič
revize
5038a336be

+ 22 - 17
modules/gdscript/gdscript_parser.cpp

@@ -1439,27 +1439,32 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
 		valid = false;
 	}
 
-	if (match(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
+	if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
+		push_multiline(true);
+		advance();
 		// Arguments.
 		push_completion_call(annotation);
 		make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, 0, true);
-		if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
-			push_multiline(true);
-			int argument_index = 0;
-			do {
-				make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, argument_index, true);
-				set_last_completion_call_arg(argument_index++);
-				ExpressionNode *argument = parse_expression(false);
-				if (argument == nullptr) {
-					valid = false;
-					continue;
-				}
-				annotation->arguments.push_back(argument);
-			} while (match(GDScriptTokenizer::Token::COMMA));
-			pop_multiline();
+		int argument_index = 0;
+		do {
+			if (check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
+				// Allow for trailing comma.
+				break;
+			}
 
-			consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after annotation arguments.)*");
-		}
+			make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, argument_index, true);
+			set_last_completion_call_arg(argument_index++);
+			ExpressionNode *argument = parse_expression(false);
+			if (argument == nullptr) {
+				push_error("Expected expression as the annotation argument.");
+				valid = false;
+				continue;
+			}
+			annotation->arguments.push_back(argument);
+		} while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
+
+		pop_multiline();
+		consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after annotation arguments.)*");
 		pop_completion_call();
 	}
 	complete_extents(annotation);

+ 4 - 0
modules/gdscript/tests/scripts/parser/errors/annotation_extra_comma.gd

@@ -0,0 +1,4 @@
+@export_enum("A",, "B", "C") var a
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/parser/errors/annotation_extra_comma.out

@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression as the annotation argument.

+ 48 - 0
modules/gdscript/tests/scripts/parser/features/annotations.gd

@@ -0,0 +1,48 @@
+extends Node
+
+@export_enum("A", "B", "C") var a0
+@export_enum("A", "B", "C",) var a1
+
+@export_enum(
+	"A",
+	"B",
+	"C"
+) var a2
+
+@export_enum(
+	"A",
+	"B",
+	"C",
+) var a3
+
+@export
+var a4: int
+
+@export()
+var a5: int
+
+@export() var a6: int
+@warning_ignore("onready_with_export") @onready @export var a7: int
+@warning_ignore("onready_with_export") @onready() @export() var a8: int
+
+@warning_ignore("onready_with_export")
+@onready
+@export
+var a9: int
+
+@warning_ignore("onready_with_export")
+@onready()
+@export()
+var a10: int
+
+@warning_ignore("onready_with_export")
+@onready()
+@export()
+
+var a11: int
+
+
+func test():
+	for property in get_property_list():
+		if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
+			print(property)

+ 13 - 0
modules/gdscript/tests/scripts/parser/features/annotations.out

@@ -0,0 +1,13 @@
+GDTEST_OK
+{ "name": "a0", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 }
+{ "name": "a1", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 }
+{ "name": "a2", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 }
+{ "name": "a3", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 }
+{ "name": "a4", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a5", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a6", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a7", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a8", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a9", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a10", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }
+{ "name": "a11", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 }