瀏覽代碼

Parse C# generics and type constraints correctly

Carter Anderson 6 年之前
父節點
當前提交
d339824f15

+ 2 - 0
modules/mono/editor/GodotSharpTools/.gitignore

@@ -0,0 +1,2 @@
+# nuget packages
+packages

+ 97 - 4
modules/mono/editor/script_class_parser.cpp

@@ -259,6 +259,8 @@ Error ScriptClassParser::_skip_generic_type_params() {
 				if (err)
 					return err;
 				continue;
+			} else if (tk == TK_OP_GREATER) {
+				return OK;
 			} else if (tk != TK_COMMA) {
 				error_str = "Unexpected token: " + get_token_name(tk);
 				error = true;
@@ -312,27 +314,108 @@ Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
 
 	Token tk = get_token();
 
+	bool generic = false;
 	if (tk == TK_OP_LESS) {
-		// We don't add it to the base list if it's generic
 		Error err = _skip_generic_type_params();
 		if (err)
 			return err;
-	} else if (tk == TK_COMMA) {
+		// We don't add it to the base list if it's generic
+		generic = true;
+		tk = get_token();
+	}
+
+	if (tk == TK_COMMA) {
 		Error err = _parse_class_base(r_base);
 		if (err)
 			return err;
-		r_base.push_back(name);
+	} else if (tk == TK_IDENTIFIER && String(value) == "where") {
+		Error err = _parse_type_constraints();
+		if (err) {
+			return err;
+		}
+
+		// An open curly bracket was parsed by _parse_type_constraints, so we can exit
 	} else if (tk == TK_CURLY_BRACKET_OPEN) {
-		r_base.push_back(name);
+		// we are finished when we hit the open curly bracket
 	} else {
 		error_str = "Unexpected token: " + get_token_name(tk);
 		error = true;
 		return ERR_PARSE_ERROR;
 	}
 
+	if (!generic) {
+		r_base.push_back(name);
+	}
+
 	return OK;
 }
 
+Error ScriptClassParser::_parse_type_constraints() {
+	Token tk = get_token();
+	if (tk != TK_IDENTIFIER) {
+		error_str = "Unexpected token: " + get_token_name(tk);
+		error = true;
+		return ERR_PARSE_ERROR;
+	}
+
+	tk = get_token();
+	if (tk != TK_COLON) {
+		error_str = "Unexpected token: " + get_token_name(tk);
+		error = true;
+		return ERR_PARSE_ERROR;
+	}
+
+	while (true) {
+		tk = get_token();
+		if (tk == TK_IDENTIFIER) {
+			if (String(value) == "where") {
+				return _parse_type_constraints();
+			}
+
+			tk = get_token();
+			if (tk == TK_PERIOD) {
+				while (true) {
+					tk = get_token();
+
+					if (tk != TK_IDENTIFIER) {
+						error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
+						error = true;
+						return ERR_PARSE_ERROR;
+					}
+
+					tk = get_token();
+
+					if (tk != TK_PERIOD)
+						break;
+				}
+			}
+		}
+
+		if (tk == TK_COMMA) {
+			continue;
+		} else if (tk == TK_IDENTIFIER && String(value) == "where") {
+			return _parse_type_constraints();
+		} else if (tk == TK_SYMBOL && String(value) == "(") {
+			tk = get_token();
+			if (tk != TK_SYMBOL || String(value) != ")") {
+				error_str = "Unexpected token: " + get_token_name(tk);
+				error = true;
+				return ERR_PARSE_ERROR;
+			}
+		} else if (tk == TK_OP_LESS) {
+			Error err = _skip_generic_type_params();
+			if (err)
+				return err;
+		} else if (tk == TK_CURLY_BRACKET_OPEN) {
+			return OK;
+		} else {
+			error_str = "Unexpected token: " + get_token_name(tk);
+			error = true;
+			return ERR_PARSE_ERROR;
+		}
+	}
+}
+
 Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
 
 	Token tk = get_token();
@@ -425,6 +508,16 @@ Error ScriptClassParser::parse(const String &p_code) {
 						Error err = _skip_generic_type_params();
 						if (err)
 							return err;
+					} else if (tk == TK_IDENTIFIER && String(value) == "where") {
+						Error err = _parse_type_constraints();
+						if (err) {
+							return err;
+						}
+
+						// An open curly bracket was parsed by _parse_type_constraints, so we can exit
+						curly_stack++;
+						type_curly_stack++;
+						break;
 					} else {
 						error_str = "Unexpected token: " + get_token_name(tk);
 						error = true;

+ 1 - 0
modules/mono/editor/script_class_parser.h

@@ -65,6 +65,7 @@ private:
 
 	Error _parse_type_full_name(String &r_full_name);
 	Error _parse_class_base(Vector<String> &r_base);
+	Error _parse_type_constraints();
 	Error _parse_namespace_name(String &r_name, int &r_curly_stack);
 
 public: