Browse Source

Fix parsing inner class declaration when "pass" keyword is on the same line

Implement a special case for allowing "pass" keyword in one-liner class
declaration, to be consistent with Python style.

```
class TestClass: pass
```

This commit fixes #56703
Kirill Diduk 3 years ago
parent
commit
5bcc3d476c
2 changed files with 62 additions and 19 deletions
  1. 59 19
      modules/gdscript/gdscript_parser.cpp
  2. 3 0
      modules/gdscript/gdscript_parser.h

+ 59 - 19
modules/gdscript/gdscript_parser.cpp

@@ -82,8 +82,51 @@ void GDScriptParser::_set_end_statement_error(String p_name) {
 }
 
 bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
+	if (!_parse_colon()) {
+		return false;
+	}
+
+	if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) {
+		// Be more Python-like.
+		IndentLevel current_level = indent_level.back()->get();
+		indent_level.push_back(current_level);
+		return true;
+	}
+
+	return _parse_indent_block_newlines(p_block);
+}
+
+bool GDScriptParser::_enter_inner_class_indent_block() {
+	if (!_parse_colon()) {
+		return false;
+	}
+
+	if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) {
+		// Check Python-like one-liner class declaration "class Foo: pass".
+		// Note: only "pass" is allowed on the same line after the colon.
+		if (tokenizer->get_token() != GDScriptTokenizer::TK_CF_PASS) {
+			return false;
+		}
+
+		GDScriptTokenizer::Token token = tokenizer->get_token(1);
+		if (token != GDScriptTokenizer::TK_NEWLINE && token != GDScriptTokenizer::TK_EOF) {
+			int line = tokenizer->get_token_line();
+			int col = tokenizer->get_token_column();
+			String message = "Invalid syntax: unexpected \"";
+			message += GDScriptTokenizer::get_token_name(token);
+			message += "\".";
+			_set_error(message, line, col);
+			return false;
+		}
+		return true;
+	}
+
+	return _parse_indent_block_newlines();
+}
+
+bool GDScriptParser::_parse_colon() {
 	if (tokenizer->get_token() != GDScriptTokenizer::TK_COLON) {
-		// report location at the previous token (on the previous line)
+		// Report location at the previous token (on the previous line).
 		int error_line = tokenizer->get_token_line(-1);
 		int error_column = tokenizer->get_token_column(-1);
 		_set_error("':' expected at end of line.", error_line, error_column);
@@ -95,19 +138,12 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
 		return false;
 	}
 
-	if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) {
-		// be more python-like
-		IndentLevel current_level = indent_level.back()->get();
-		indent_level.push_back(current_level);
-		return true;
-		//_set_error("newline expected after ':'.");
-		//return false;
-	}
+	return true;
+}
 
+bool GDScriptParser::_parse_indent_block_newlines(BlockNode *p_block) {
 	while (true) {
-		if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) {
-			return false; //wtf
-		} else if (tokenizer->get_token(1) == GDScriptTokenizer::TK_EOF) {
+		if (tokenizer->get_token(1) == GDScriptTokenizer::TK_EOF) {
 			return false;
 		} else if (tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE) {
 			int indent = tokenizer->get_token_line_indent();
@@ -126,14 +162,13 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
 			indent_level.push_back(new_indent);
 			tokenizer->advance();
 			return true;
-
 		} else if (p_block) {
 			NewLineNode *nl = alloc_node<NewLineNode>();
 			nl->line = tokenizer->get_token_line();
 			p_block->statements.push_back(nl);
 		}
 
-		tokenizer->advance(); // go to next newline
+		tokenizer->advance(); // Go to the next newline.
 	}
 }
 
@@ -3840,13 +3875,18 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 					}
 				}
 
-				if (!_enter_indent_block()) {
-					_set_error("Indented block expected.");
+				if (!_enter_inner_class_indent_block()) {
+					if (!error_set) {
+						_set_error("Indented block or \"pass\" expected.");
+					}
 					return;
 				}
-				current_class = newclass;
-				_parse_class(newclass);
-				current_class = p_class;
+
+				if (tokenizer->get_token() != GDScriptTokenizer::TK_CF_PASS) {
+					current_class = newclass;
+					_parse_class(newclass);
+					current_class = p_class;
+				}
 
 			} break;
 			/* this is for functions....

+ 3 - 0
modules/gdscript/gdscript_parser.h

@@ -599,6 +599,9 @@ private:
 
 	bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false, bool p_parsing_constant = false);
 	bool _enter_indent_block(BlockNode *p_block = nullptr);
+	bool _enter_inner_class_indent_block();
+	bool _parse_colon();
+	bool _parse_indent_block_newlines(BlockNode *p_block = nullptr);
 	bool _parse_newline();
 	Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false);
 	Node *_reduce_expression(Node *p_node, bool p_to_const = false);