From e3d72d14ff27af2b396397065ddc38f87685c694 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 29 May 2018 23:16:57 -0300 Subject: [PATCH] Use type information to enable GDScript introspection This makes the Script API provide accurate information when requesting property or method info. --- modules/gdscript/gdscript.cpp | 20 ++--- modules/gdscript/gdscript.h | 1 + modules/gdscript/gdscript_compiler.cpp | 110 +++++++++++++++---------- modules/gdscript/gdscript_compiler.h | 3 + modules/gdscript/gdscript_parser.cpp | 50 +++++++++++ modules/gdscript/gdscript_parser.h | 43 +--------- 6 files changed, 129 insertions(+), 98 deletions(-) diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index a8916c2a2e0..8bd29ffc556 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -220,16 +220,14 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { void GDScript::get_script_method_list(List *p_list) const { for (const Map::Element *E = member_functions.front(); E; E = E->next()) { + GDScriptFunction *func = E->get(); MethodInfo mi; mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); + for (int i = 0; i < func->get_argument_count(); i++) { + mi.arguments.push_back(func->get_argument_type(i)); } - mi.return_val.name = "Variant"; + mi.return_val = func->get_return_type(); p_list->push_back(mi); } } @@ -277,16 +275,14 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const { if (!E) return MethodInfo(); + GDScriptFunction *func = E->get(); MethodInfo mi; mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); + for (int i = 0; i < func->get_argument_count(); i++) { + mi.arguments.push_back(func->get_argument_type(i)); } - mi.return_val.name = "Variant"; + mi.return_val = func->get_return_type(); return mi; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 5c6cda09937..98196f0b0e6 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -152,6 +152,7 @@ public: } const Map &get_member_functions() const { return member_functions; } const Ref &get_native() const { return native; } + const String &get_script_class_name() const { return name; } virtual bool has_script_signal(const StringName &p_signal) const; virtual void get_script_signal_list(List *r_signals) const; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 46ff52f42b3..a428ccd3062 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -111,23 +111,50 @@ bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptP return true; } -/* -int GDScriptCompiler::_parse_subexpression(CodeGen& codegen,const GDScriptParser::Node *p_expression) { - - - int ret = _parse_expression(codegen,p_expression); - if (ret<0) - return ret; - - if (ret&(GDScriptFunction::ADDR_TYPE_STACK<get_instance_base_type(); + } + case GDScriptParser::DataType::GDSCRIPT: { + result.kind = GDScriptDataType::GDSCRIPT; + result.script_type = p_datatype.script_type; + result.native_type = result.script_type->get_instance_base_type(); + } break; + case GDScriptParser::DataType::CLASS: { + result.kind = GDScriptDataType::GDSCRIPT; + if (p_datatype.class_type->name == StringName()) { + result.script_type = Ref(main_script); + } else { + result.script_type = class_map[p_datatype.class_type->name]; + } + result.native_type = result.script_type->get_instance_base_type(); + } break; + default: { + ERR_PRINT("Parser bug: converting unresolved type."); + result.has_type = false; + } + } + + return result; } -*/ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level) { @@ -1883,41 +1910,41 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner for (int i = 0; i < p_class->variables.size(); i++) { StringName name = p_class->variables[i].identifier; - if (p_script->member_indices.has(name)) { - _set_error("Member '" + name + "' already exists (in current or parent class)", p_class); - return ERR_ALREADY_EXISTS; - } - if (_is_class_member_property(p_script, name)) { - _set_error("Member '" + name + "' already exists as a class property.", p_class); - return ERR_ALREADY_EXISTS; - } - if (p_class->variables[i]._export.type != Variant::NIL) { - - p_script->member_info[name] = p_class->variables[i]._export; -#ifdef TOOLS_ENABLED - if (p_class->variables[i].default_value.get_type() != Variant::NIL) { - - p_script->member_default_values[name] = p_class->variables[i].default_value; - } -#endif - } else { - - p_script->member_info[name] = PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); - } - - //int new_idx = p_script->member_indices.size(); GDScript::MemberInfo minfo; minfo.index = p_script->member_indices.size(); minfo.setter = p_class->variables[i].setter; minfo.getter = p_class->variables[i].getter; minfo.rpc_mode = p_class->variables[i].rpc_mode; + minfo.data_type = _gdtype_from_datatype(p_class->variables[i].data_type); + PropertyInfo prop_info = minfo.data_type; + prop_info.name = name; + PropertyInfo export_info = p_class->variables[i]._export; + + if (export_info.type != Variant::NIL) { + + if (!minfo.data_type.has_type) { + prop_info.type = export_info.type; + prop_info.class_name = export_info.class_name; + } + prop_info.hint = export_info.hint; + prop_info.hint_string = export_info.hint_string; + prop_info.usage = export_info.usage; +#ifdef TOOLS_ENABLED + if (p_class->variables[i].default_value.get_type() != Variant::NIL) { + p_script->member_default_values[name] = p_class->variables[i].default_value; + } +#endif + } else { + prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE; + } + + p_script->member_info[name] = prop_info; p_script->member_indices[name] = minfo; p_script->members.insert(name); #ifdef TOOLS_ENABLED - p_script->member_lines[name] = p_class->variables[i].line; #endif } @@ -1928,15 +1955,9 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner ERR_CONTINUE(E->get().expression->type != GDScriptParser::Node::TYPE_CONSTANT); - if (_is_class_member_property(p_script, name)) { - _set_error("Member '" + name + "' already exists as a class property.", p_class); - return ERR_ALREADY_EXISTS; - } - GDScriptParser::ConstantNode *constant = static_cast(E->get().expression); p_script->constants.insert(name, constant->value); -//p_script->constants[constant->value].make_const(); #ifdef TOOLS_ENABLED p_script->member_lines[name] = E->get().expression->line; @@ -2144,6 +2165,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri err_column = -1; error = ""; parser = p_parser; + main_script = p_script; const GDScriptParser::Node *root = parser->get_parse_tree(); ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, ERR_INVALID_DATA); diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 19df9bd7223..55f5e2b48eb 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -41,6 +41,7 @@ class GDScriptCompiler { Map > class_map; Set parsed_classes; Set parsing_classes; + GDScript *main_script; struct CodeGen { GDScript *script; @@ -142,6 +143,8 @@ class GDScriptCompiler { bool _create_unary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level); bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false); + GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const; + int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level); int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false); Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index cfabb4812d5..5a281511610 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -4957,6 +4957,56 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { } } +String GDScriptParser::DataType::to_string() const { + if (!has_type) return "var"; + switch (kind) { + case BUILTIN: { + if (builtin_type == Variant::NIL) return "null"; + return Variant::get_type_name(builtin_type); + } break; + case NATIVE: { + if (is_meta_type) { + return "GDScriptNativeClass"; + } + return native_type.operator String(); + } break; + + case GDSCRIPT: { + Ref gds = script_type; + const String &gds_class = gds->get_script_class_name(); + if (!gds_class.empty()) { + return gds_class; + } + } // fallthrough + case SCRIPT: { + if (is_meta_type) { + return script_type->get_class_name().operator String(); + } + String name = script_type->get_name(); + if (name != String()) { + return name; + } + name = script_type->get_path().get_file(); + if (name != String()) { + return name; + } + return native_type.operator String(); + } break; + case CLASS: { + ERR_FAIL_COND_V(!class_type, String()); + if (is_meta_type) { + return "GDScript"; + } + if (class_type->name == StringName()) { + return "self"; + } + return class_type->name.operator String(); + } break; + } + + return "Unresolved"; +} + bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) { tokenizer->advance(); r_type.has_type = true; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 258dab2677d..e9be25efc7b 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -62,48 +62,7 @@ public: Ref