1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-06 12:20:30 +00:00

Parse C# script namespace and class

- Added a very simple parser that can extract the namespace and class name of a C# script.
This commit is contained in:
Ignacio Etcheverry
2018-10-22 19:43:19 +02:00
parent c6e2873605
commit 1aac95a737
14 changed files with 891 additions and 53 deletions

View File

@@ -30,11 +30,15 @@
#include "csharp_project.h"
#include "core/io/json.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "../csharp_script.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/string_utils.h"
#include "script_class_parser.h"
namespace CSharpProject {
@@ -118,4 +122,109 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
ERR_FAIL();
}
}
Error generate_scripts_metadata(const String &p_project_path, const String &p_output_path) {
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
void *args[2] = {
GDMonoMarshal::mono_string_from_godot(p_project_path),
GDMonoMarshal::mono_string_from_godot("Compile")
};
MonoException *exc = NULL;
MonoArray *ret = (MonoArray *)project_utils->get_method("GetIncludeFiles", 2)->invoke_raw(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL_V(FAILED);
}
PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret);
PoolStringArray::Read r = project_files.read();
Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata();
Dictionary new_dict;
for (int i = 0; i < project_files.size(); i++) {
const String &project_file = ("res://" + r[i]).simplify_path();
uint64_t modified_time = FileAccess::get_modified_time(project_file);
const Variant *old_file_var = old_dict.getptr(project_file);
if (old_file_var) {
Dictionary old_file_dict = old_file_var->operator Dictionary();
if (old_file_dict["modified_time"].operator uint64_t() == modified_time) {
// No changes so no need to parse again
new_dict[project_file] = old_file_dict;
continue;
}
}
ScriptClassParser scp;
Error err = scp.parse_file(project_file);
if (err != OK) {
ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file);
ERR_FAIL_V(err);
}
Vector<ScriptClassParser::ClassDecl> classes = scp.get_classes();
bool found = false;
Dictionary class_dict;
String search_name = project_file.get_file().get_basename();
for (int j = 0; j < classes.size(); j++) {
const ScriptClassParser::ClassDecl &class_decl = classes[j];
if (class_decl.base.size() == 0)
continue; // Does not inherit nor implement anything, so it can't be a script class
String class_cmp;
if (class_decl.nested) {
class_cmp = class_decl.name.get_slice(".", class_decl.name.get_slice_count(".") - 1);
} else {
class_cmp = class_decl.name;
}
if (class_cmp != search_name)
continue;
class_dict["namespace"] = class_decl.namespace_;
class_dict["class_name"] = class_decl.name;
class_dict["nested"] = class_decl.nested;
found = true;
break;
}
if (found) {
Dictionary file_dict;
file_dict["modified_time"] = modified_time;
file_dict["class"] = class_dict;
new_dict[project_file] = file_dict;
}
}
if (new_dict.size()) {
String json = JSON::print(new_dict, "", false);
Error ferr;
FileAccess *f = FileAccess::open(p_output_path, FileAccess::WRITE, &ferr);
ERR_EXPLAIN("Cannot open file for writing: " + p_output_path);
ERR_FAIL_COND_V(ferr != OK, ferr);
f->store_string(json);
f->flush();
f->close();
memdelete(f);
}
return OK;
}
} // namespace CSharpProject