diff options
Diffstat (limited to 'modules/mono/editor')
-rw-r--r-- | modules/mono/editor/GodotSharpTools/.gitignore | 2 | ||||
-rw-r--r-- | modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs | 36 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.cpp | 140 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.h | 6 | ||||
-rw-r--r-- | modules/mono/editor/csharp_project.cpp | 20 | ||||
-rw-r--r-- | modules/mono/editor/dotnet_solution.cpp (renamed from modules/mono/editor/net_solution.cpp) | 61 | ||||
-rw-r--r-- | modules/mono/editor/dotnet_solution.h (renamed from modules/mono/editor/net_solution.h) | 23 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_builds.cpp | 74 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_builds.h | 4 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_editor.cpp | 32 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_export.cpp | 2 | ||||
-rw-r--r-- | modules/mono/editor/mono_bottom_panel.cpp | 10 | ||||
-rw-r--r-- | modules/mono/editor/script_class_parser.cpp | 211 | ||||
-rw-r--r-- | modules/mono/editor/script_class_parser.h | 10 |
14 files changed, 413 insertions, 218 deletions
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/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs index 574b711b29..2ce7837a27 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs @@ -6,22 +6,24 @@ namespace GodotSharpTools.Project { public static class ProjectGenerator { + public const string CoreApiProjectName = "GodotSharp"; + public const string EditorApiProjectName = "GodotSharpEditor"; const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}"; const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}"; public static string GenCoreApiProject(string dir, string[] compileItems) { - string path = Path.Combine(dir, CoreApiProject + ".csproj"); + string path = Path.Combine(dir, CoreApiProjectName + ".csproj"); ProjectPropertyGroupElement mainGroup; - var root = CreateLibraryProject(CoreApiProject, out mainGroup); + var root = CreateLibraryProject(CoreApiProjectName, out mainGroup); mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); mainGroup.SetProperty("RootNamespace", "Godot"); mainGroup.SetProperty("ProjectGuid", CoreApiProjectGuid); - GenAssemblyInfoFile(root, dir, CoreApiProject, - new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" }, + GenAssemblyInfoFile(root, dir, CoreApiProjectName, + new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]" }, new string[] { "System.Runtime.CompilerServices" }); foreach (var item in compileItems) @@ -31,34 +33,33 @@ namespace GodotSharpTools.Project root.Save(path); - return root.GetGuid().ToString().ToUpper(); + return CoreApiProjectGuid; } - public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems) + public static string GenEditorApiProject(string dir, string coreApiProjPath, string[] compileItems) { - string path = Path.Combine(dir, EditorApiProject + ".csproj"); + string path = Path.Combine(dir, EditorApiProjectName + ".csproj"); ProjectPropertyGroupElement mainGroup; - var root = CreateLibraryProject(EditorApiProject, out mainGroup); + var root = CreateLibraryProject(EditorApiProjectName, out mainGroup); mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); mainGroup.SetProperty("RootNamespace", "Godot"); mainGroup.SetProperty("ProjectGuid", EditorApiProjectGuid); - GenAssemblyInfoFile(root, dir, EditorApiProject); + GenAssemblyInfoFile(root, dir, EditorApiProjectName); foreach (var item in compileItems) { root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); } - var coreApiRef = root.AddItem("Reference", CoreApiProject); - coreApiRef.AddMetadata("HintPath", coreApiHintPath); + var coreApiRef = root.AddItem("ProjectReference", coreApiProjPath.Replace("/", "\\")); coreApiRef.AddMetadata("Private", "False"); root.Save(path); - return root.GetGuid().ToString().ToUpper(); + return EditorApiProjectGuid; } public static string GenGameProject(string dir, string name, string[] compileItems) @@ -82,13 +83,13 @@ namespace GodotSharpTools.Project toolsGroup.AddProperty("WarningLevel", "4"); toolsGroup.AddProperty("ConsolePause", "false"); - var coreApiRef = root.AddItem("Reference", CoreApiProject); - coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll")); + var coreApiRef = root.AddItem("Reference", CoreApiProjectName); + coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll")); coreApiRef.AddMetadata("Private", "False"); - var editorApiRef = root.AddItem("Reference", EditorApiProject); + var editorApiRef = root.AddItem("Reference", EditorApiProjectName); editorApiRef.Condition = " '$(Configuration)' == 'Tools' "; - editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll")); + editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll")); editorApiRef.AddMetadata("Private", "False"); GenAssemblyInfoFile(root, dir, name); @@ -187,9 +188,6 @@ namespace GodotSharpTools.Project } } - public const string CoreApiProject = "GodotSharp"; - public const string EditorApiProject = "GodotSharpEditor"; - private const string assemblyInfoTemplate = @"using System.Reflection;{0} diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 710682d3aa..166b3e1324 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -47,7 +47,6 @@ #include "../utils/path_utils.h" #include "../utils/string_utils.h" #include "csharp_project.h" -#include "net_solution.h" #define CS_INDENT " " // 4 whitespaces @@ -401,32 +400,29 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { p_output.push_back(CLOSE_BLOCK); // end of namespace } -Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) { +Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { verbose_output = p_verbose_output; + String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); - if (!DirAccess::exists(p_output_dir)) { - Error err = da->make_dir_recursive(p_output_dir); + if (!DirAccess::exists(proj_dir)) { + Error err = da->make_dir_recursive(proj_dir); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); } - da->change_dir(p_output_dir); + da->change_dir(proj_dir); da->make_dir("Core"); da->make_dir("ObjectType"); - String core_dir = path_join(p_output_dir, "Core"); - String obj_type_dir = path_join(p_output_dir, "ObjectType"); + String core_dir = path_join(proj_dir, "Core"); + String obj_type_dir = path_join(proj_dir, "ObjectType"); Vector<String> compile_items; - NETSolution solution(API_ASSEMBLY_NAME); - - if (!solution.set_path(p_output_dir)) - return ERR_FILE_NOT_FOUND; - // Generate source file for global scope constants and enums { List<String> constants_source; @@ -530,15 +526,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo compile_items.push_back(internal_methods_file); - String guid = CSharpProject::generate_core_api_project(p_output_dir, compile_items); + String guid = CSharpProject::generate_core_api_project(proj_dir, compile_items); - solution.add_new_project(API_ASSEMBLY_NAME, guid); + DotNetSolution::ProjectInfo proj_info; + proj_info.guid = guid; + proj_info.relpath = String(CORE_API_ASSEMBLY_NAME).plus_file(CORE_API_ASSEMBLY_NAME ".csproj"); + proj_info.configs.push_back("Debug"); + proj_info.configs.push_back("Release"); - Error sln_error = solution.save(); - if (sln_error != OK) { - ERR_PRINT("Could not to save .NET solution."); - return sln_error; - } + r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info); if (verbose_output) OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n"); @@ -546,32 +542,29 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo return OK; } -Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output) { +Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { verbose_output = p_verbose_output; + String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); - if (!DirAccess::exists(p_output_dir)) { - Error err = da->make_dir_recursive(p_output_dir); + if (!DirAccess::exists(proj_dir)) { + Error err = da->make_dir_recursive(proj_dir); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); } - da->change_dir(p_output_dir); + da->change_dir(proj_dir); da->make_dir("Core"); da->make_dir("ObjectType"); - String core_dir = path_join(p_output_dir, "Core"); - String obj_type_dir = path_join(p_output_dir, "ObjectType"); + String core_dir = path_join(proj_dir, "Core"); + String obj_type_dir = path_join(proj_dir, "ObjectType"); Vector<String> compile_items; - NETSolution solution(EDITOR_API_ASSEMBLY_NAME); - - if (!solution.set_path(p_output_dir)) - return ERR_FILE_NOT_FOUND; - for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { const TypeInterface &itype = E.get(); @@ -632,19 +625,57 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, compile_items.push_back(internal_methods_file); - String guid = CSharpProject::generate_editor_api_project(p_output_dir, p_core_dll_path, compile_items); + String guid = CSharpProject::generate_editor_api_project(proj_dir, "../" CORE_API_ASSEMBLY_NAME "/" CORE_API_ASSEMBLY_NAME ".csproj", compile_items); + + DotNetSolution::ProjectInfo proj_info; + proj_info.guid = guid; + proj_info.relpath = String(EDITOR_API_ASSEMBLY_NAME).plus_file(EDITOR_API_ASSEMBLY_NAME ".csproj"); + proj_info.configs.push_back("Debug"); + proj_info.configs.push_back("Release"); + + r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info); + + if (verbose_output) + OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n"); + + return OK; +} - solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, guid); +Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) { + + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + + if (!DirAccess::exists(p_output_dir)) { + Error err = da->make_dir_recursive(p_output_dir); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + } + + DotNetSolution solution(API_SOLUTION_NAME); + + if (!solution.set_path(p_output_dir)) + return ERR_FILE_NOT_FOUND; + + Error proj_err; + + proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output); + if (proj_err != OK) { + ERR_PRINT("Generation of the Core API C# project failed"); + return proj_err; + } + + proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output); + if (proj_err != OK) { + ERR_PRINT("Generation of the Editor API C# project failed"); + return proj_err; + } Error sln_error = solution.save(); if (sln_error != OK) { - ERR_PRINT("Could not to save .NET solution."); + ERR_PRINT("Failed to save API solution"); return sln_error; } - if (verbose_output) - OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n"); - return OK; } @@ -2368,12 +2399,11 @@ void BindingsGenerator::initialize() { void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) { - const int NUM_OPTIONS = 3; + const int NUM_OPTIONS = 2; int options_left = NUM_OPTIONS; String mono_glue_option = "--generate-mono-glue"; - String cs_core_api_option = "--generate-cs-core-api"; - String cs_editor_api_option = "--generate-cs-editor-api"; + String cs_api_option = "--generate-cs-api"; verbose_output = true; @@ -2387,42 +2417,24 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) if (path_elem) { if (get_singleton()->generate_glue(path_elem->get()) != OK) - ERR_PRINT("Mono glue generation failed"); + ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue"); elem = elem->next(); } else { - ERR_PRINTS("--generate-mono-glue: No output directory specified"); + ERR_PRINTS(mono_glue_option + ": No output directory specified"); } --options_left; - } else if (elem->get() == cs_core_api_option) { + } else if (elem->get() == cs_api_option) { const List<String>::Element *path_elem = elem->next(); if (path_elem) { - if (get_singleton()->generate_cs_core_project(path_elem->get()) != OK) - ERR_PRINT("Generation of solution and C# project for the Core API failed"); + if (get_singleton()->generate_cs_api(path_elem->get()) != OK) + ERR_PRINTS(cs_api_option + ": Failed to generate the C# API"); elem = elem->next(); } else { - ERR_PRINTS(cs_core_api_option + ": No output directory specified"); - } - - --options_left; - - } else if (elem->get() == cs_editor_api_option) { - - const List<String>::Element *path_elem = elem->next(); - - if (path_elem) { - if (path_elem->next()) { - if (get_singleton()->generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK) - ERR_PRINT("Generation of solution and C# project for the Editor API failed"); - elem = path_elem->next(); - } else { - ERR_PRINTS(cs_editor_api_option + ": No hint path for the Core API dll specified"); - } - } else { - ERR_PRINTS(cs_editor_api_option + ": No output directory specified"); + ERR_PRINTS(cs_api_option + ": No output directory specified"); } --options_left; @@ -2434,7 +2446,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) verbose_output = false; if (options_left != NUM_OPTIONS) - exit(0); + ::exit(0); } #endif diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 38cf99c294..91c474c4f0 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -32,6 +32,7 @@ #define BINDINGS_GENERATOR_H #include "core/class_db.h" +#include "dotnet_solution.h" #include "editor/doc/doc_data.h" #include "editor/editor_help.h" @@ -556,8 +557,9 @@ class BindingsGenerator { static BindingsGenerator *singleton; public: - Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true); - Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true); + Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true); + Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true); + Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true); Error generate_glue(const String &p_output_dir); static uint32_t get_version(); diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp index 03db765c2e..416108603b 100644 --- a/modules/mono/editor/csharp_project.cpp +++ b/modules/mono/editor/csharp_project.cpp @@ -31,6 +31,8 @@ #include "csharp_project.h" #include "core/io/json.h" +#include "core/os/dir_access.h" +#include "core/os/file_access.h" #include "core/os/os.h" #include "core/project_settings.h" @@ -62,16 +64,16 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); } -String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) { +String generate_editor_api_project(const String &p_dir, const String &p_core_proj_path, const Vector<String> &p_files) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator"); Variant dir = p_dir; - Variant core_dll_path = p_core_dll_path; + Variant core_proj_path = p_core_proj_path; Variant compile_items = p_files; - const Variant *args[3] = { &dir, &core_dll_path, &compile_items }; + const Variant *args[3] = { &dir, &core_proj_path, &compile_items }; MonoException *exc = NULL; MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc); @@ -106,6 +108,9 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) { + if (!GLOBAL_DEF("mono/project/auto_update_project", true)) + return; + _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils"); @@ -127,6 +132,14 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) + if (FileAccess::exists(p_output_path)) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Error rm_err = da->remove(p_output_path); + + ERR_EXPLAIN("Failed to remove old scripts metadata file"); + ERR_FAIL_COND_V(rm_err != OK, rm_err); + } + GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils"); void *args[2] = { @@ -167,6 +180,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/net_solution.cpp b/modules/mono/editor/dotnet_solution.cpp index a000debe52..ab92e2e378 100644 --- a/modules/mono/editor/net_solution.cpp +++ b/modules/mono/editor/dotnet_solution.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* net_solution.cpp */ +/* dotnet_solution.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "net_solution.h" +#include "dotnet_solution.h" #include "core/os/dir_access.h" #include "core/os/file_access.h" @@ -58,27 +58,26 @@ "\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \ "\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU" -void NETSolution::add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs) { - if (projects.has(p_name)) - WARN_PRINT("Overriding existing project."); - - ProjectInfo procinfo; - procinfo.guid = p_guid; +void DotNetSolution::add_new_project(const String &p_name, const ProjectInfo &p_project_info) { + projects[p_name] = p_project_info; +} - procinfo.configs.push_back("Debug"); - procinfo.configs.push_back("Release"); +bool DotNetSolution::has_project(const String &p_name) const { + return projects.find(p_name) != NULL; +} - for (int i = 0; i < p_extra_configs.size(); i++) { - procinfo.configs.push_back(p_extra_configs[i]); - } +const DotNetSolution::ProjectInfo &DotNetSolution::get_project_info(const String &p_name) const { + return projects[p_name]; +} - projects[p_name] = procinfo; +bool DotNetSolution::remove_project(const String &p_name) { + return projects.erase(p_name); } -Error NETSolution::save() { +Error DotNetSolution::save() { bool dir_exists = DirAccess::exists(path); ERR_EXPLAIN("The directory does not exist."); - ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH); + ERR_FAIL_COND_V(!dir_exists, ERR_FILE_NOT_FOUND); String projs_decl; String sln_platform_cfg; @@ -86,34 +85,40 @@ Error NETSolution::save() { for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) { const String &name = E->key(); - const ProjectInfo &procinfo = E->value(); + const ProjectInfo &proj_info = E->value(); - projs_decl += sformat(PROJECT_DECLARATION, name, name + ".csproj", procinfo.guid); + bool is_front = E == projects.front(); - for (int i = 0; i < procinfo.configs.size(); i++) { - const String &config = procinfo.configs[i]; + if (!is_front) + projs_decl += "\n"; - if (i != 0) { + projs_decl += sformat(PROJECT_DECLARATION, name, proj_info.relpath.replace("/", "\\"), proj_info.guid); + + for (int i = 0; i < proj_info.configs.size(); i++) { + const String &config = proj_info.configs[i]; + + if (i != 0 || !is_front) { sln_platform_cfg += "\n"; proj_platform_cfg += "\n"; } sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config); - proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, procinfo.guid, config); + proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, proj_info.guid, config); } } String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg); - FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE); - ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); + FileAccess *file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE); + ERR_FAIL_NULL_V(file, ERR_FILE_CANT_WRITE); file->store_string(content); file->close(); + memdelete(file); return OK; } -bool NETSolution::set_path(const String &p_existing_path) { +bool DotNetSolution::set_path(const String &p_existing_path) { if (p_existing_path.is_abs_path()) { path = p_existing_path; } else { @@ -126,6 +131,10 @@ bool NETSolution::set_path(const String &p_existing_path) { return true; } -NETSolution::NETSolution(const String &p_name) { +String DotNetSolution::get_path() { + return path; +} + +DotNetSolution::DotNetSolution(const String &p_name) { name = p_name; } diff --git a/modules/mono/editor/net_solution.h b/modules/mono/editor/dotnet_solution.h index bdff24af0b..629605ad18 100644 --- a/modules/mono/editor/net_solution.h +++ b/modules/mono/editor/dotnet_solution.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* net_solution.h */ +/* dotnet_solution.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,23 +34,28 @@ #include "core/map.h" #include "core/ustring.h" -struct NETSolution { +struct DotNetSolution { String name; - void add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs = Vector<String>()); + struct ProjectInfo { + String guid; + String relpath; // Must be relative to the solution directory + Vector<String> configs; + }; + + void add_new_project(const String &p_name, const ProjectInfo &p_project_info); + bool has_project(const String &p_name) const; + const ProjectInfo &get_project_info(const String &p_name) const; + bool remove_project(const String &p_name); Error save(); bool set_path(const String &p_existing_path); + String get_path(); - NETSolution(const String &p_name); + DotNetSolution(const String &p_name); private: - struct ProjectInfo { - String guid; - Vector<String> configs; - }; - String path; Map<String, ProjectInfo> projects; }; diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 6216213716..0f12fc5243 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -227,20 +227,24 @@ void GodotSharpBuilds::show_build_error_dialog(const String &p_message) { MonoBottomPanel::get_singleton()->show_build_tab(); } -bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config) { +bool GodotSharpBuilds::build_api_sln(const String &p_api_sln_dir, const String &p_config) { - String api_sln_file = p_api_sln_dir.plus_file(p_name + ".sln"); - String api_assembly_dir = p_api_sln_dir.plus_file("bin").plus_file(p_config); - String api_assembly_file = api_assembly_dir.plus_file(p_name + ".dll"); + String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln"); - if (!FileAccess::exists(api_assembly_file)) { + String core_api_assembly_dir = p_api_sln_dir.plus_file(CORE_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config); + String core_api_assembly_file = core_api_assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); + + String editor_api_assembly_dir = p_api_sln_dir.plus_file(EDITOR_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config); + String editor_api_assembly_file = editor_api_assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + + if (!FileAccess::exists(core_api_assembly_file) || !FileAccess::exists(editor_api_assembly_file)) { MonoBuildInfo api_build_info(api_sln_file, p_config); // TODO Replace this global NoWarn with '#pragma warning' directives on generated files, // once we start to actively document manually maintained C# classes api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) { - show_build_error_dialog("Failed to build " + p_name + " solution."); + show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution."); return false; } } @@ -302,9 +306,9 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) { "_" + String::num_uint64(CS_GLUE_VERSION); } -bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { +bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) { - String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; + String api_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir(); String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); @@ -317,55 +321,35 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { String api_build_config = "Release"; - EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3); + EditorProgress pr("mono_build_release_" API_SOLUTION_NAME, "Building " API_SOLUTION_NAME " solution...", 3); - pr.step("Generating " + api_name + " solution", 0); + pr.step("Generating " API_SOLUTION_NAME " solution", 0); - String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() - .plus_file(_api_folder_name(APIAssembly::API_CORE)) - .plus_file(API_ASSEMBLY_NAME); - String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() - .plus_file(_api_folder_name(APIAssembly::API_EDITOR)) - .plus_file(EDITOR_API_ASSEMBLY_NAME); + String api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() + .plus_file(_api_folder_name(APIAssembly::API_CORE)); - String api_sln_dir = p_api_type == APIAssembly::API_CORE ? core_api_sln_dir : editor_api_sln_dir; - String api_sln_file = api_sln_dir.plus_file(api_name + ".sln"); + String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln"); if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) { - String core_api_assembly; - - if (p_api_type == APIAssembly::API_EDITOR) { - core_api_assembly = core_api_sln_dir.plus_file("bin") - .plus_file(api_build_config) - .plus_file(API_ASSEMBLY_NAME ".dll"); - } - -#ifndef DEBUG_METHODS_ENABLED -#error "How am I supposed to generate the bindings?" -#endif - BindingsGenerator *gen = BindingsGenerator::get_singleton(); bool gen_verbose = OS::get_singleton()->is_stdout_verbose(); - Error err = p_api_type == APIAssembly::API_CORE ? - gen->generate_cs_core_project(api_sln_dir, gen_verbose) : - gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose); - + Error err = gen->generate_cs_api(api_sln_dir, gen_verbose); if (err != OK) { - show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err)); + show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err)); return false; } } - pr.step("Building " + api_name + " solution", 1); + pr.step("Building " API_SOLUTION_NAME " solution", 1); - if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config)) + if (!GodotSharpBuilds::build_api_sln(api_sln_dir, api_build_config)) return false; pr.step("Copying " + api_name + " assembly", 2); // Copy the built assembly to the assemblies directory - String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config); + String api_assembly_dir = api_sln_dir.plus_file(api_name).plus_file("bin").plus_file(api_build_config); if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type)) return false; @@ -377,10 +361,10 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) { if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) return true; // No solution to build - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE)) return false; - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR)) return false; EditorProgress pr("mono_project_debug_build", "Building project solution...", 1); @@ -403,11 +387,13 @@ bool GodotSharpBuilds::editor_build_callback() { Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor); ERR_FAIL_COND_V(metadata_err != OK, false); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player); + if (FileAccess::exists(scripts_metadata_path_editor)) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player); - ERR_EXPLAIN("Failed to copy scripts metadata file"); - ERR_FAIL_COND_V(copy_err != OK, false); + ERR_EXPLAIN("Failed to copy scripts metadata file"); + ERR_FAIL_COND_V(copy_err != OK, false); + } return build_project_blocking("Tools"); } diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index c6dc6b6236..7f38b0aa49 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -84,10 +84,10 @@ public: bool build(const MonoBuildInfo &p_build_info); bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL); - static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config); + static bool build_api_sln(const String &p_api_sln_dir, const String &p_config); static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type); - static bool make_api_sln(APIAssembly::Type p_api_type); + static bool make_api_assembly(APIAssembly::Type p_api_type); static bool build_project_blocking(const String &p_config); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 9df4e10266..cce86efbf5 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -42,8 +42,8 @@ #include "../utils/path_utils.h" #include "bindings_generator.h" #include "csharp_project.h" +#include "dotnet_solution.h" #include "godotsharp_export.h" -#include "net_solution.h" #ifdef OSX_ENABLED #include "../utils/osx_utils.h" @@ -71,17 +71,21 @@ bool GodotSharpEditor::_create_project_solution() { if (guid.length()) { - NETSolution solution(name); + DotNetSolution solution(name); if (!solution.set_path(path)) { show_error_dialog(TTR("Failed to create solution.")); return false; } - Vector<String> extra_configs; - extra_configs.push_back("Tools"); + DotNetSolution::ProjectInfo proj_info; + proj_info.guid = guid; + proj_info.relpath = name + ".csproj"; + proj_info.configs.push_back("Debug"); + proj_info.configs.push_back("Release"); + proj_info.configs.push_back("Tools"); - solution.add_new_project(name, guid, extra_configs); + solution.add_new_project(name, proj_info); Error sln_error = solution.save(); @@ -90,10 +94,10 @@ bool GodotSharpEditor::_create_project_solution() { return false; } - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE)) return false; - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR)) return false; pr.step(TTR("Done")); @@ -122,15 +126,15 @@ void GodotSharpEditor::_make_api_solutions_if_needed_impl() { // If the project has a solution and C# project make sure the API assemblies are present and up to date String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); - if (!FileAccess::exists(res_assemblies_dir.plus_file(API_ASSEMBLY_NAME ".dll")) || + if (!FileAccess::exists(res_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll")) || GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) { - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE)) return; } if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) || GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) + if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR)) return; // Redundant? I don't think so } } @@ -471,7 +475,9 @@ MonoReloadNode *MonoReloadNode::singleton = NULL; void MonoReloadNode::_reload_timer_timeout() { - CSharpLanguage::get_singleton()->reload_assemblies_if_needed(false); + if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) { + CSharpLanguage::get_singleton()->reload_assemblies(false); + } } void MonoReloadNode::restart_reload_timer() { @@ -489,7 +495,9 @@ void MonoReloadNode::_notification(int p_what) { switch (p_what) { case MainLoop::NOTIFICATION_WM_FOCUS_IN: { restart_reload_timer(); - CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true); + if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) { + CSharpLanguage::get_singleton()->reload_assemblies(false); + } } break; default: { } break; diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 509ec961fb..34c710320a 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -117,7 +117,7 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug GDMonoAssembly *scripts_assembly = NULL; bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name, - project_dll_src_dir, &scripts_assembly, /* refonly: */ true); + project_dll_src_path, &scripts_assembly, /* refonly: */ true); ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name); ERR_FAIL_COND(!load_success); diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index d7bfa54aba..e89d21d92d 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -154,10 +154,14 @@ void MonoBottomPanel::_build_project_pressed() { Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path); ERR_FAIL_COND(metadata_err != OK); - GodotSharpBuilds::get_singleton()->build_project_blocking("Tools"); + bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools"); - MonoReloadNode::get_singleton()->restart_reload_timer(); - CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true); + if (build_success) { + MonoReloadNode::get_singleton()->restart_reload_timer(); + if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) { + CSharpLanguage::get_singleton()->reload_assemblies(false); + } + } } void MonoBottomPanel::_view_log_pressed() { 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; } diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h index 11cf1853e2..184adebaf2 100644 --- a/modules/mono/editor/script_class_parser.h +++ b/modules/mono/editor/script_class_parser.h @@ -52,14 +52,20 @@ 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<String> &r_base); + Error _parse_type_constraints(); Error _parse_namespace_name(String &r_name, int &r_curly_stack); public: |