Merge pull request #23336 from neikeq/dd

Fix C# parsing the full name of base types
This commit is contained in:
Ignacio Etcheverry 2018-10-28 01:44:40 +02:00 committed by GitHub
commit aeddb30fa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 45 deletions

View File

@ -167,6 +167,7 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou
ScriptClassParser scp; ScriptClassParser scp;
Error err = scp.parse_file(project_file); Error err = scp.parse_file(project_file);
if (err != OK) { if (err != OK) {
ERR_PRINTS("Parse error: " + scp.get_error());
ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file); ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file);
ERR_FAIL_V(err); ERR_FAIL_V(err);
} }

View File

@ -5,6 +5,30 @@
#include "../utils/string_utils.h" #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, "<error>");
return token_names[p_token];
}
ScriptClassParser::Token ScriptClassParser::get_token() { ScriptClassParser::Token ScriptClassParser::get_token() {
while (true) { while (true) {
@ -203,7 +227,7 @@ ScriptClassParser::Token ScriptClassParser::get_token() {
} }
} }
Error ScriptClassParser::_skip_type_parameters() { Error ScriptClassParser::_skip_generic_type_params() {
Token tk; Token tk;
@ -213,68 +237,100 @@ Error ScriptClassParser::_skip_type_parameters() {
if (tk == TK_IDENTIFIER) { if (tk == TK_IDENTIFIER) {
tk = get_token(); 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) { if (tk == TK_OP_LESS) {
Error err = _skip_type_parameters(); Error err = _skip_generic_type_params();
if (err) if (err)
return err; return err;
continue; continue;
} else if (tk != TK_COMMA) { } else if (tk != TK_COMMA) {
error_str = "Unexpected token: " + itos(tk); error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
} else if (tk == TK_OP_LESS) { } 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; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} else if (tk == TK_OP_GREATER) { } else if (tk == TK_OP_GREATER) {
return OK; return OK;
} else { } else {
error_str = "Unexpected token: " + itos(tk); error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; 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<String> &r_base) { Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
Token tk; String name;
while (true) { Error err = _parse_type_full_name(name);
tk = get_token(); if (err)
return err;
if (tk == TK_IDENTIFIER) { Token tk = get_token();
bool generic = false;
String name = value;
tk = get_token();
if (tk == TK_OP_LESS) { if (tk == TK_OP_LESS) {
generic = true; // We don't add it to the base list if it's generic
Error err = _skip_type_parameters(); Error err = _skip_generic_type_params();
if (err) if (err)
return err; return err;
} else if (tk == TK_COMMA) { } else if (tk == TK_COMMA) {
Error err = _parse_class_base(r_base); Error err = _parse_class_base(r_base);
if (err) if (err)
return err; return err;
} else if (tk != TK_CURLY_BRACKET_OPEN) { r_base.push_back(name);
error_str = "Unexpected token: " + itos(tk); } else if (tk == TK_CURLY_BRACKET_OPEN) {
r_base.push_back(name);
} else {
error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
r_base.push_back(!generic ? name : String()); // no generics, please
return OK; return OK;
} else {
error_str = "Unexpected token: " + itos(tk);
error = true;
return ERR_PARSE_ERROR;
}
}
} }
Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) { 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) { if (tk == TK_IDENTIFIER) {
r_name += String(value); r_name += String(value);
} else { } else {
error_str = "Unexpected token: " + itos(tk); error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -298,7 +354,7 @@ Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stac
r_curly_stack++; r_curly_stack++;
return OK; return OK;
} else { } else {
error_str = "Unexpected token: " + itos(tk); error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -366,11 +422,11 @@ Error ScriptClassParser::parse(const String &p_code) {
} else if (tk == TK_OP_LESS && !generic) { } else if (tk == TK_OP_LESS && !generic) {
generic = true; generic = true;
Error err = _skip_type_parameters(); Error err = _skip_generic_type_params();
if (err) if (err)
return err; return err;
} else { } else {
error_str = "Unexpected token: " + itos(tk); error_str = "Unexpected token: " + get_token_name(tk);
error = true; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -400,7 +456,7 @@ Error ScriptClassParser::parse(const String &p_code) {
name = String(value); name = String(value);
} else if (tk == TK_CURLY_BRACKET_OPEN) { } else if (tk == TK_CURLY_BRACKET_OPEN) {
if (name.empty()) { 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; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -409,7 +465,7 @@ Error ScriptClassParser::parse(const String &p_code) {
type_curly_stack++; type_curly_stack++;
break; break;
} else if (tk == TK_EOF) { } 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; error = true;
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }

View File

@ -52,13 +52,18 @@ private:
TK_OP_LESS, TK_OP_LESS,
TK_OP_GREATER, TK_OP_GREATER,
TK_EOF, 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(); 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<String> &r_base); Error _parse_class_base(Vector<String> &r_base);
Error _parse_namespace_name(String &r_name, int &r_curly_stack); Error _parse_namespace_name(String &r_name, int &r_curly_stack);