summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gd_compiler.cpp19
-rw-r--r--modules/gdscript/gd_editor.cpp437
-rw-r--r--modules/gdscript/gd_parser.cpp9
-rw-r--r--modules/gdscript/gd_parser.h3
-rw-r--r--modules/gdscript/gd_script.h15
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);