From d339824f154074454a783a4a2a517199df2d7c35 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 4 Nov 2018 16:51:59 -0800 Subject: Parse C# generics and type constraints correctly --- modules/mono/editor/GodotSharpTools/.gitignore | 2 + modules/mono/editor/script_class_parser.cpp | 101 ++++++++++++++++++++++++- modules/mono/editor/script_class_parser.h | 1 + 3 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 modules/mono/editor/GodotSharpTools/.gitignore (limited to 'modules/mono') diff --git a/modules/mono/editor/GodotSharpTools/.gitignore b/modules/mono/editor/GodotSharpTools/.gitignore new file mode 100644 index 0000000000..296ad48834 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/.gitignore @@ -0,0 +1,2 @@ +# nuget packages +packages \ No newline at end of file diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index bc8eed81cf..9042bff74a 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/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 &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; diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h index 1e174c28a9..184adebaf2 100644 --- a/modules/mono/editor/script_class_parser.h +++ b/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 &r_base); + Error _parse_type_constraints(); Error _parse_namespace_name(String &r_name, int &r_curly_stack); public: -- cgit v1.2.3