summaryrefslogtreecommitdiffstats
path: root/modules/mono/editor/script_class_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/editor/script_class_parser.cpp')
-rw-r--r--modules/mono/editor/script_class_parser.cpp211
1 files changed, 180 insertions, 31 deletions
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
index 43de8df2b2..9042bff74a 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, "<error>");
+ 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,64 +237,179 @@ 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_OP_GREATER) {
+ return OK;
} 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<String> &r_base) {
- Token tk;
+ String name;
- while (true) {
+ Error err = _parse_type_full_name(name);
+ if (err)
+ return err;
+
+ Token tk = get_token();
+
+ bool generic = false;
+ if (tk == TK_OP_LESS) {
+ Error err = _skip_generic_type_params();
+ if (err)
+ return err;
+ // We don't add it to the base list if it's generic
+ generic = true;
tk = get_token();
+ }
- if (tk == TK_IDENTIFIER) {
- bool generic = false;
+ if (tk == TK_COMMA) {
+ Error err = _parse_class_base(r_base);
+ 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
+ } else if (tk == TK_CURLY_BRACKET_OPEN) {
+ // 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;
+ }
- String name = value;
+ 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_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);
+ 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;
}
-
- r_base.push_back(!generic ? name : String()); // no generics, please
-
+ } 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: " + itos(tk);
+ error_str = "Unexpected token: " + get_token_name(tk);
error = true;
return ERR_PARSE_ERROR;
}
@@ -284,7 +423,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 +437,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 +505,21 @@ 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 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: " + itos(tk);
+ error_str = "Unexpected token: " + get_token_name(tk);
error = true;
return ERR_PARSE_ERROR;
}
@@ -400,7 +549,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 +558,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;
}