From 2cf02f302fd39e75af557737be61b891bebabc30 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Sun, 28 Oct 2018 01:31:17 +0200 Subject: [PATCH] Fix C# parsing the full name of base types Previously it would fail if the type name included its namespace. --- modules/mono/editor/csharp_project.cpp | 1 + modules/mono/editor/script_class_parser.cpp | 142 ++++++++++++++------ modules/mono/editor/script_class_parser.h | 9 +- 3 files changed, 107 insertions(+), 45 deletions(-) diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp index 03db765c2e0..ab96356d6d6 100644 --- a/modules/mono/editor/csharp_project.cpp +++ b/modules/mono/editor/csharp_project.cpp @@ -167,6 +167,7 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou ScriptClassParser scp; Error err = scp.parse_file(project_file); if (err != OK) { + ERR_PRINTS("Parse error: " + scp.get_error()); ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file); ERR_FAIL_V(err); } diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index 43de8df2b2c..bc8eed81cfe 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/modules/mono/editor/script_class_parser.cpp @@ -5,6 +5,30 @@ #include "../utils/string_utils.h" +const char *ScriptClassParser::token_names[ScriptClassParser::TK_MAX] = { + "[", + "]", + "{", + "}", + ".", + ":", + ",", + "Symbol", + "Identifier", + "String", + "Number", + "<", + ">", + "EOF", + "Error" +}; + +String ScriptClassParser::get_token_name(ScriptClassParser::Token p_token) { + + ERR_FAIL_INDEX_V(p_token, TK_MAX, ""); + return token_names[p_token]; +} + ScriptClassParser::Token ScriptClassParser::get_token() { while (true) { @@ -203,7 +227,7 @@ ScriptClassParser::Token ScriptClassParser::get_token() { } } -Error ScriptClassParser::_skip_type_parameters() { +Error ScriptClassParser::_skip_generic_type_params() { Token tk; @@ -213,68 +237,100 @@ Error ScriptClassParser::_skip_type_parameters() { if (tk == TK_IDENTIFIER) { 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_OP_LESS) { - Error err = _skip_type_parameters(); + Error err = _skip_generic_type_params(); if (err) return err; continue; } else if (tk != TK_COMMA) { - error_str = "Unexpected token: " + itos(tk); + error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } else if (tk == TK_OP_LESS) { - error_str = "Expected identifier before `<`."; + error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS); error = true; return ERR_PARSE_ERROR; } else if (tk == TK_OP_GREATER) { return OK; } else { - error_str = "Unexpected token: " + itos(tk); + error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } } +Error ScriptClassParser::_parse_type_full_name(String &r_full_name) { + + Token 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; + } + + r_full_name += String(value); + + if (code[idx] != '.') // We only want to take the next token if it's a period + return OK; + + tk = get_token(); + + CRASH_COND(tk != TK_PERIOD); // Assertion + + r_full_name += "."; + + return _parse_type_full_name(r_full_name); +} + Error ScriptClassParser::_parse_class_base(Vector &r_base) { - Token tk; + String name; - while (true) { - tk = get_token(); + Error err = _parse_type_full_name(name); + if (err) + return err; - if (tk == TK_IDENTIFIER) { - bool generic = false; + Token tk = get_token(); - String name = value; - - tk = get_token(); - - if (tk == TK_OP_LESS) { - generic = true; - Error err = _skip_type_parameters(); - if (err) - return err; - } else if (tk == TK_COMMA) { - Error err = _parse_class_base(r_base); - if (err) - return err; - } else if (tk != TK_CURLY_BRACKET_OPEN) { - error_str = "Unexpected token: " + itos(tk); - error = true; - return ERR_PARSE_ERROR; - } - - r_base.push_back(!generic ? name : String()); // no generics, please - - return OK; - } else { - error_str = "Unexpected token: " + itos(tk); - error = true; - return ERR_PARSE_ERROR; - } + 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) { + Error err = _parse_class_base(r_base); + if (err) + return err; + r_base.push_back(name); + } else if (tk == TK_CURLY_BRACKET_OPEN) { + r_base.push_back(name); + } else { + error_str = "Unexpected token: " + get_token_name(tk); + error = true; + return ERR_PARSE_ERROR; } + + return OK; } Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) { @@ -284,7 +340,7 @@ Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stac if (tk == TK_IDENTIFIER) { r_name += String(value); } else { - error_str = "Unexpected token: " + itos(tk); + error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } @@ -298,7 +354,7 @@ Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stac r_curly_stack++; return OK; } else { - error_str = "Unexpected token: " + itos(tk); + error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } @@ -366,11 +422,11 @@ Error ScriptClassParser::parse(const String &p_code) { } else if (tk == TK_OP_LESS && !generic) { generic = true; - Error err = _skip_type_parameters(); + Error err = _skip_generic_type_params(); if (err) return err; } else { - error_str = "Unexpected token: " + itos(tk); + error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } @@ -400,7 +456,7 @@ Error ScriptClassParser::parse(const String &p_code) { name = String(value); } else if (tk == TK_CURLY_BRACKET_OPEN) { if (name.empty()) { - error_str = "Expected identifier after keyword `struct`. Found `{`."; + error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN); error = true; return ERR_PARSE_ERROR; } @@ -409,7 +465,7 @@ Error ScriptClassParser::parse(const String &p_code) { type_curly_stack++; break; } else if (tk == TK_EOF) { - error_str = "Expected `{` after struct decl. Found `EOF`."; + error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF); error = true; return ERR_PARSE_ERROR; } diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h index 11cf1853e2f..1e174c28a99 100644 --- a/modules/mono/editor/script_class_parser.h +++ b/modules/mono/editor/script_class_parser.h @@ -52,13 +52,18 @@ private: TK_OP_LESS, TK_OP_GREATER, TK_EOF, - TK_ERROR + TK_ERROR, + TK_MAX }; + static const char *token_names[TK_MAX]; + static String get_token_name(Token p_token); + Token get_token(); - Error _skip_type_parameters(); + Error _skip_generic_type_params(); + Error _parse_type_full_name(String &r_full_name); Error _parse_class_base(Vector &r_base); Error _parse_namespace_name(String &r_name, int &r_curly_stack);