From e5ebc9710df36d99f53f63380d6dcfed74f52887 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 21 Sep 2021 14:13:23 -0300 Subject: [PATCH] GDScript: Allow classes declaration to be done in single line Incidentally, allow multiple statements in single line functions when using semicolon as a terminator. --- modules/gdscript/gdscript_parser.cpp | 23 +++++++++++++------ modules/gdscript/gdscript_parser.h | 2 +- .../features/semicolon_as_terminator.gd | 22 ++++++++++++++++++ .../features/semicolon_as_terminator.out | 10 ++++++++ .../features/single_line_declaration.gd | 11 +++++++++ .../features/single_line_declaration.out | 3 +++ 6 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd create mode 100644 modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out create mode 100644 modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd create mode 100644 modules/gdscript/tests/scripts/parser/features/single_line_declaration.out diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index c901d9f68f8..62db436ad64 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -579,7 +579,7 @@ void GDScriptParser::parse_program() { } } - parse_class_body(); + parse_class_body(true); #ifdef TOOLS_ENABLED for (Map::Element *E = tokenizer.get_comments().front(); E; E = E->next()) { @@ -615,9 +615,10 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() { } consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after class declaration.)"); - consume(GDScriptTokenizer::Token::NEWLINE, R"(Expected newline after class declaration.)"); - if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) { + bool multiline = match(GDScriptTokenizer::Token::NEWLINE); + + if (multiline && !consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) { current_class = previous_class; return n_class; } @@ -630,9 +631,11 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() { end_statement("superclass"); } - parse_class_body(); + parse_class_body(multiline); - consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)"); + if (multiline) { + consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)"); + } current_class = previous_class; return n_class; @@ -747,7 +750,7 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() } } -void GDScriptParser::parse_class_body() { +void GDScriptParser::parse_class_body(bool p_is_multiline) { bool class_end = false; while (!class_end && !is_at_end()) { switch (current.type) { @@ -793,6 +796,9 @@ void GDScriptParser::parse_class_body() { if (panic_mode) { synchronize(); } + if (!p_is_multiline) { + class_end = true; + } } } @@ -1358,6 +1364,9 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, int error_count = 0; do { + if (!multiline && previous.type == GDScriptTokenizer::Token::SEMICOLON && check(GDScriptTokenizer::Token::NEWLINE)) { + break; + } Node *statement = parse_statement(); if (statement == nullptr) { if (error_count++ > 100) { @@ -1398,7 +1407,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, break; } - } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end()); + } while ((multiline || previous.type == GDScriptTokenizer::Token::SEMICOLON) && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end()); if (multiline) { if (!lambda_ended) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index a641c1052d3..dd7667d2919 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1324,7 +1324,7 @@ private: ClassNode *parse_class(); void parse_class_name(); void parse_extends(); - void parse_class_body(); + void parse_class_body(bool p_is_multiline); template void parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind); SignalNode *parse_signal(); diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd new file mode 100644 index 00000000000..0f4aebb459d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd @@ -0,0 +1,22 @@ +#GDTEST_OK + +func test(): + a(); + b(); + c(); + d(); + e(); + +func a(): print("a"); + +func b(): print("b1"); print("b2") + +func c(): print("c1"); print("c2"); + +func d(): + print("d1"); + print("d2") + +func e(): + print("e1"); + print("e2"); diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out new file mode 100644 index 00000000000..387cbd8fc2d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out @@ -0,0 +1,10 @@ +GDTEST_OK +a +b1 +b2 +c1 +c2 +d1 +d2 +e1 +e2 diff --git a/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd new file mode 100644 index 00000000000..650500663b2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd @@ -0,0 +1,11 @@ +#GDTEST_OK + +func test(): C.new().test("Ok"); test2() + +func test2(): print("Ok 2") + +class A: pass + +class B extends RefCounted: pass + +class C extends RefCounted: func test(x): print(x) diff --git a/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out new file mode 100644 index 00000000000..e021923dc2c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out @@ -0,0 +1,3 @@ +GDTEST_OK +Ok +Ok 2