diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gd_compiler.cpp | 19 | ||||
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 437 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.h | 3 | ||||
-rw-r--r-- | modules/gdscript/gd_script.h | 15 |
5 files changed, 482 insertions, 1 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 923f8090f7..2e2cbe7b29 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -1443,6 +1443,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * #endif if (p_func) { gdfunc->_initial_line=p_func->line; +#ifdef TOOLS_ENABLED + + p_script->member_lines[func_name]=p_func->line; +#endif } else { gdfunc->_initial_line=0; } @@ -1672,6 +1676,12 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa 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 + + } for(int i=0;i<p_class->constant_expressions.size();i++) { @@ -1683,6 +1693,11 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa p_script->constants.insert(name,constant->value); //p_script->constants[constant->value].make_const(); +#ifdef TOOLS_ENABLED + + p_script->member_lines[name]=p_class->constant_expressions[i].expression->line; +#endif + } for(int i=0;i<p_class->_signals.size();i++) { @@ -1731,6 +1746,10 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa if (err) return err; +#ifdef TOOLS_ENABLED + + p_script->member_lines[name]=p_class->subclasses[i]->line; +#endif p_script->constants.insert(name,subclass); //once parsed, goes to the list of constants p_script->subclasses.insert(name,subclass); diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 29dbe82a47..48b58c16b8 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -351,6 +351,7 @@ struct GDCompletionIdentifier { Ref<GDScript> script; Variant::Type type; Variant value; //im case there is a value, also return it + }; @@ -935,6 +936,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: return false; } + static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) { @@ -2522,3 +2524,438 @@ void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_ } } + +Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol,const String& p_base_path, Object*p_owner,LookupResult& r_result) { + + + //before parsing, try the usual stuff + if (ObjectTypeDB::type_exists(p_symbol)) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=p_symbol; + return OK; + } + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + Variant::Type t = Variant::Type(i); + if (Variant::get_type_name(t)==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=Variant::get_type_name(t); + return OK; + } + } + + for(int i=0;i<GDFunctions::FUNC_MAX;i++) { + if (GDFunctions::get_func_name(GDFunctions::Function(i))==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name="@GDScript"; + r_result.class_member=p_symbol; + return OK; + } + } + + GDParser p; + p.parse(p_code,p_base_path,false,"",true); + + if (p.get_completion_type()==GDParser::COMPLETION_NONE) + return ERR_CANT_RESOLVE; + + GDCompletionContext context; + + context._class=p.get_completion_class(); + context.block=p.get_completion_block(); + context.function=p.get_completion_function(); + context.base=p_owner; + context.base_path=p_base_path; + bool isfunction=false; + + switch(p.get_completion_type()) { + + case GDParser::COMPLETION_NONE: { + } break; + case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=Variant::get_type_name(p.get_completion_built_in_constant()); + r_result.class_member=p_symbol; + return OK; + + } break; + case GDParser::COMPLETION_FUNCTION: { + + + if (context._class && context._class->functions.size()) { + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->functions[i]->line; + return OK; + } + } + } + + Ref<GDScript> parent = _get_parent_class(context); + while(parent.is_valid()) { + int line = parent->get_member_line(p_symbol); + if (line>=0) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=line; + r_result.script=parent; + return OK; + + } + + parent=parent->get_base(); + } + + GDCompletionIdentifier identifier = _get_native_class(context); + print_line("identifier: "+String(identifier.obj_type)); + + if (ObjectTypeDB::has_method(identifier.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=identifier.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + + } break; + case GDParser::COMPLETION_IDENTIFIER: { + + //check if a function + if (p.get_completion_identifier_is_function()) { + if (context._class && context._class->functions.size()) { + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->functions[i]->line; + return OK; + } + } + } + + Ref<GDScript> parent = _get_parent_class(context); + while(parent.is_valid()) { + int line = parent->get_member_line(p_symbol); + if (line>=0) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=line; + r_result.script=parent; + return OK; + + } + + parent=parent->get_base(); + } + + GDCompletionIdentifier identifier = _get_native_class(context); + + + if (ObjectTypeDB::has_method(identifier.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=identifier.obj_type; + r_result.class_member=p_symbol; + return OK; + } + } else { + + + const GDParser::BlockNode *block=context.block; + //search in blocks going up (local var?) + while(block) { + + + + for (int i=0;i<block->statements.size();i++) { + + if (block->statements[i]->line>p.get_completion_line()) + continue; + + + if (block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) { + + const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(block->statements[i]); + + if (lv->assign && lv->name==p_symbol) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=block->statements[i]->line; + return OK; + } + } + } + block=block->parent_block; + } + + //guess from function arguments + if (context.function && context.function->name!=StringName()) { + + for(int i=0;i<context.function->arguments.size();i++) { + + if (context.function->arguments[i]==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context.function->line; + return OK; + } + + } + } + + //guess in class constants + + for(int i=0;i<context._class->constant_expressions.size();i++) { + + if (context._class->constant_expressions[i].identifier==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->constant_expressions[i].expression->line; + return OK; + } + } + + //guess in class variables + if (!(context.function && context.function->_static)) { + + for(int i=0;i<context._class->variables.size();i++) { + + if (context._class->variables[i].identifier==p_symbol) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->variables[i].line; + return OK; + } + } + } + + //guess in autoloads as singletons + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { + + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + String name = s.get_slice("/",1); + if (name==String(p_symbol)) { + + String path = Globals::get_singleton()->get(s); + if (path.begins_with("*")) { + String script =path.substr(1,path.length()); + + if (!script.ends_with(".gd")) { + //not a script, try find the script anyway, + //may have some success + script=script.basename()+".gd"; + } + + if (FileAccess::exists(script)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=0; + r_result.script=ResourceLoader::load(script); + return OK; + } + } + } + } + + //global + for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) { + if (E->key()==p_symbol) { + + Variant value = GDScriptLanguage::get_singleton()->get_global_array()[E->get()]; + if (value.get_type()==Variant::OBJECT) { + Object *obj = value; + if (obj) { + + if (obj->cast_to<GDNativeClass>()) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=obj->cast_to<GDNativeClass>()->get_name(); + + } else { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=obj->get_type(); + } + return OK; + } + } else { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name="@Global Scope"; + r_result.class_member=p_symbol; + return OK; + } + } + + } +#if 0 + GDCompletionIdentifier identifier; + if (_guess_identifier_type(context,p.get_completion_line(),p_symbol,identifier)) { + + print_line("var type: "+Variant::get_type_name(identifier.type)); + if (identifier.script.is_valid()) { + print_line("var script: "+identifier.script->get_path()); + } + print_line("obj type: "+String(identifier.obj_type)); + print_line("value: "+String(identifier.value)); + } +#endif + } + + } break; + case GDParser::COMPLETION_PARENT_FUNCTION: { + + } break; + case GDParser::COMPLETION_METHOD: + isfunction=true; + case GDParser::COMPLETION_INDEX: { + + const GDParser::Node *node = p.get_completion_node(); + if (node->type!=GDParser::Node::TYPE_OPERATOR) + break; + + + + + GDCompletionIdentifier t; + if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) { + + if (t.type==Variant::OBJECT && t.obj_type=="GDNativeClass") { + //native enum + Ref<GDNativeClass> gdn = t.value; + if (gdn.is_valid()) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=gdn->get_name();; + r_result.class_member=p_symbol; + return OK; + + } + } else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + + Ref<GDScript> on_script; + + if (t.value.get_type()) { + Object *obj=t.value; + + + if (obj) { + + + on_script=obj->get_script(); + + if (on_script.is_valid()) { + int loc = on_script->get_member_line(p_symbol); + if (loc>=0) { + r_result.script=on_script; + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=loc; + return OK; + } + } + } + } + + if (ObjectTypeDB::has_method(t.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + + } + + bool success; + ObjectTypeDB::get_integer_constant(t.obj_type,p_symbol,&success); + if (success) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + ObjectTypeDB::get_property_type(t.obj_type,p_symbol,&success); + + if (success) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + + } else { + + Variant::CallError ce; + Variant v = Variant::construct(t.type,NULL,0,ce); + + bool valid; + v.get_numeric_constant_value(t.type,p_symbol,&valid); + if (valid) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + } + + //todo check all inputevent types for property + + v.get(p_symbol,&valid); + + if (valid) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + } + + if (v.has_method(p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + + } + + + } + } + + + } break; + case GDParser::COMPLETION_CALL_ARGUMENTS: { + + return ERR_CANT_RESOLVE; + } break; + case GDParser::COMPLETION_VIRTUAL_FUNC: { + + GDCompletionIdentifier cid = _get_native_class(context); + + if (cid.obj_type!=StringName()) { + List<MethodInfo> vm; + ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm); + for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) { + + if (p_symbol==E->get().name) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=cid.obj_type; + r_result.class_member=p_symbol; + return OK; + + } + } + } + } break; + case GDParser::COMPLETION_YIELD: { + + return ERR_CANT_RESOLVE; + + } break; + + } + + + return ERR_CANT_RESOLVE; +} diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 2bebcb5fe1..8f4f5ef4ca 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -203,6 +203,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide completion_line=tokenizer->get_token_line(); completion_block=current_block; completion_found=true; + completion_ident_is_call=false; tokenizer->advance(); if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { @@ -210,6 +211,9 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide tokenizer->advance(); } + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + completion_ident_is_call=true; + } return true; } @@ -3552,6 +3556,11 @@ int GDParser::get_completion_argument_index() { return completion_argument; } +int GDParser::get_completion_identifier_is_function() { + + return completion_ident_is_call; +} + GDParser::GDParser() { head=NULL; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index aca77e0df0..75653e0916 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -432,6 +432,7 @@ private: int completion_line; int completion_argument; bool completion_found; + bool completion_ident_is_call; PropertyInfo current_export; @@ -478,7 +479,7 @@ public: BlockNode *get_completion_block(); FunctionNode *get_completion_function(); int get_completion_argument_index(); - + int get_completion_identifier_is_function(); void clear(); GDParser(); diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 0c3e1eb614..cb20361068 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -65,6 +65,7 @@ class GDScript : public Script { StringName setter; StringName getter; ScriptInstance::RPCMode rpc_mode; + }; friend class GDInstance; @@ -86,8 +87,11 @@ friend class GDScriptLanguage; Map<StringName,Ref<GDScript> > subclasses; Map<StringName,Vector<StringName> > _signals; + #ifdef TOOLS_ENABLED + Map<StringName,int> member_lines; + Map<StringName,Variant> member_default_values; List<PropertyInfo> members_cache; @@ -193,6 +197,16 @@ public: virtual ScriptLanguage *get_language() const; + virtual int get_member_line(const StringName& p_member) const { +#ifdef TOOLS_ENABLED + if (member_lines.has(p_member)) + return member_lines[p_member]; + else +#endif + return -1; + + } + GDScript(); ~GDScript(); }; @@ -394,6 +408,7 @@ public: virtual int find_function(const String& p_function,const String& p_code) const; virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const; virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint); + virtual Error lookup_code(const String& p_code, const String& p_symbol, const String& p_base_path, Object*p_owner, LookupResult& r_result); virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const; virtual void add_global_constant(const StringName& p_variable,const Variant& p_value); |