diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 307 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 16 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.h | 5 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 166 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.h | 13 |
5 files changed, 442 insertions, 65 deletions
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index b1db087fb..546fed4e8 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -66,7 +66,7 @@ bool GDScriptLanguage::validate(const String& p_script, int &r_line_error,int &r GDParser parser; - Error err = parser.parse(p_script,p_path.get_base_dir(),true); + Error err = parser.parse(p_script,p_path.get_base_dir(),true,p_path); if (err) { r_line_error=parser.get_error_line(); r_col_error=parser.get_error_column(); @@ -421,8 +421,240 @@ static bool _parse_completion_variant(const Variant& p_var,List<String>* r_optio } +struct GDCompletionIdentifier { -static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_options,List<String>::Element *p_indices) { + StringName obj_type; + Variant::Type type; +}; + + +static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier); + + +static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,GDCompletionIdentifier &r_type) { + + + if (p_node->type==GDParser::Node::TYPE_CONSTANT) { + + const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node); + + r_type.type=cn->value.get_type(); + if (r_type.type==Variant::OBJECT) { + Object *obj = cn->value; + if (obj) { + r_type.obj_type=obj->get_type(); + } + } + + return true; + } else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) { + + r_type.type=Variant::DICTIONARY; + return true; + } else if (p_node->type==GDParser::Node::TYPE_ARRAY) { + + r_type.type=Variant::ARRAY; + return true; + + } else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { + + MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function); + r_type.type=mi.return_val.type; + if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) { + r_type.obj_type=mi.return_val.hint_string; + } + return true; + } else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) { + + + r_type=_guess_identifier_type(p_class,p_line,static_cast<const GDParser::IdentifierNode *>(p_node)->name); + return true; + } else if (p_node->type==GDParser::Node::TYPE_SELF) { + //eeh... + return false; + + } else if (p_node->type==GDParser::Node::TYPE_OPERATOR) { + const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node); + if (op->op==GDParser::OperatorNode::OP_CALL) { + + if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) { + + const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode *>(op->arguments[0]); + r_type.type=tn->vtype; + return true; + } else if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { + + + const GDParser::BuiltInFunctionNode *bin = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]); + return _guess_identifier_type_in_expression(p_class,bin,p_line,r_type); + + } else if (op->arguments.size()>1 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) { + + GDCompletionIdentifier base; + if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,base)) + return false; + StringName id = static_cast<const GDParser::IdentifierNode *>(p_node)->name; + if (base.type==Variant::OBJECT) { + + if (ObjectTypeDB::has_method(base.obj_type,id)) { +#ifdef TOOLS_ENABLED + MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id); + PropertyInfo pi = mb->get_argument_info(-1); + + r_type.type=pi.type; + if (pi.hint==PROPERTY_HINT_RESOURCE_TYPE) { + r_type.obj_type=pi.hint_string; + } +#else + return false; +#endif + } else { + return false; + } + } else { + //method for some variant.. + Variant::CallError ce; + Variant v = Variant::construct(base.type,NULL,0,ce); + List<MethodInfo> mi; + v.get_method_list(&mi); + for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { + + if (E->get().name==id.operator String()) { + + MethodInfo mi = E->get(); + r_type.type=mi.return_val.type; + if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) { + r_type.obj_type=mi.return_val.hint_string; + } + return true; + } + } + + } + + + } + } else { + + Variant::Operator vop = Variant::OP_MAX; + switch(op->op) { + case GDParser::OperatorNode::OP_ASSIGN_ADD: vop=Variant::OP_ADD; break; + case GDParser::OperatorNode::OP_ASSIGN_SUB: vop=Variant::OP_SUBSTRACT; break; + case GDParser::OperatorNode::OP_ASSIGN_MUL: vop=Variant::OP_MULTIPLY; break; + case GDParser::OperatorNode::OP_ASSIGN_DIV: vop=Variant::OP_DIVIDE; break; + case GDParser::OperatorNode::OP_ASSIGN_MOD: vop=Variant::OP_MODULE; break; + case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break; + case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break; + case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: vop=Variant::OP_BIT_AND; break; + case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: vop=Variant::OP_BIT_OR; break; + case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: vop=Variant::OP_BIT_XOR; break; + default:{} + + } + + if (vop==Variant::OP_MAX) + return false; + + GDCompletionIdentifier p1; + GDCompletionIdentifier p2; + + if (op->arguments[0]) { + if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,p1)) + return false; + } + + if (op->arguments.size()>1) { + if (!_guess_identifier_type_in_expression(p_class,op->arguments[1],p_line,p2)) + return false; + } + + Variant::CallError ce; + Variant v1 = Variant::construct(p1.type,NULL,0,ce); + Variant v2 = Variant::construct(p2.type,NULL,0,ce); + // avoid potential invalid ops + if ((vop==Variant::OP_DIVIDE || vop==Variant::OP_MODULE) && v2.get_type()==Variant::INT) { + v2=1; + } + if (vop==Variant::OP_DIVIDE && v2.get_type()==Variant::REAL) { + v2=1.0; + } + + Variant r; + bool valid; + Variant::evaluate(vop,v1,v2,r,valid); + if (!valid) + return false; + r_type.type=r.get_type(); + return true; + + } + + } + + return false; +} + +static bool _guess_identifier_type_in_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) { + + + for(int i=0;i<p_block->sub_blocks.size();i++) { + //parse inner first + if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) { + if (_guess_identifier_type_in_block(p_class,p_block->sub_blocks[i],p_line,p_identifier,r_type)) + return true; + } + } + + + + const GDParser::Node *last_assign=NULL; + int last_assign_line=-1; + + for (int i=0;i<p_block->statements.size();i++) { + + if (p_block->statements[i]->line>p_line) + break; + + + if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) { + + const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]); + if (lv->assign && lv->name==p_identifier) { + last_assign=lv->assign; + last_assign_line=p_block->statements[i]->line; + } + } + + if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) { + const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_block->statements[i]); + if (op->op==GDParser::OperatorNode::OP_ASSIGN) { + + if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) { + const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]); + if (id->name==p_identifier) { + last_assign=op->arguments[1]; + last_assign_line=p_block->statements[i]->line; + } + } + } + } + } + + //use the last assignment, (then backwards?) + if (last_assign) { + return _guess_identifier_type_in_expression(p_class,last_assign,last_assign_line-1,r_type); + } + + return false; +} + +static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier) { + + + return GDCompletionIdentifier(); +} + +static void _parse_expression_node(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,List<String>* r_options,List<String>::Element *p_indices) { @@ -433,7 +665,7 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_ } else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) { const GDParser::DictionaryNode *dn=static_cast<const GDParser::DictionaryNode*>(p_node); - for(int i=0;i<dn->elements.size();i++) { + for (int i=0;i<dn->elements.size();i++) { if (dn->elements[i].key->type==GDParser::Node::TYPE_CONSTANT) { @@ -444,7 +676,7 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_ if (p_indices) { if (str==p_indices->get()) { - _parse_expression_node(dn->elements[i].value,r_options,p_indices->next()); + _parse_expression_node(p_class,dn->elements[i].value,p_line,r_options,p_indices->next()); return; } @@ -454,15 +686,28 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_ } } } + } else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { + + MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function); + + Variant::CallError ce; + _parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL); + } else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) { + + //GDCompletionIdentifier idt = _guess_identifier_type(p_class,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name); + //Variant::CallError ce; + //_parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL); } } -static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) { +static bool _parse_completion_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) { + + print_line("COMPLETION BLOCK "+itos(p_block->line)+" -> "+itos(p_block->end_line)); for(int i=0;i<p_block->sub_blocks.size();i++) { //parse inner first if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) { - if (_parse_completion_block(p_block->sub_blocks[i],p_line,r_options,p_indices)) + if (_parse_completion_block(p_class,p_block->sub_blocks[i],p_line,r_options,p_indices)) return true; } } @@ -470,29 +715,39 @@ static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_lin if (p_indices) { //parse indices in expressions :| + + const GDParser::Node *last_assign=NULL; + int last_assign_line=-1; + for (int i=0;i<p_block->statements.size();i++) { if (p_block->statements[i]->line>p_line) break; + if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) { - const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]); + const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]); if (lv->assign && String(lv->name)==p_indices->get()) { - - _parse_expression_node(lv->assign,r_options,p_indices->next()); - return true; + last_assign=lv->assign; + last_assign_line=p_block->statements[i]->line; } } } + //use the last assignment, (then backwards?) + if (last_assign) { + _parse_expression_node(p_class,last_assign,last_assign_line,r_options,p_indices->next()); + return true; + } + } else { + //no indices, just add all variables and continue for(int i=0;i<p_block->variables.size();i++) { //parse variables second if (p_line>=p_block->variable_lines[i]) { r_options->push_back(p_block->variables[i]); - } - else break; + } else break; } } @@ -545,13 +800,15 @@ static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,Li static bool _parse_completion_class(const String& p_base_path,const GDParser::ClassNode *p_class,int p_line,List<String>* r_options,List<String>::Element *p_indices) { - - static const char*_type_names[Variant::VARIANT_MAX]={ - "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform", - "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray", - "Vector2Array","Vector3Array","ColorArray"}; + //checks known classes or built-in types for completion if (p_indices && !p_indices->next()) { + //built-in types do not have sub-classes, try these first if no sub-indices exist. + static const char*_type_names[Variant::VARIANT_MAX]={ + "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform", + "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray", + "Vector2Array","Vector3Array","ColorArray"}; + for(int i=0;i<Variant::VARIANT_MAX;i++) { if (p_indices->get()==_type_names[i]) { @@ -567,12 +824,12 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl } } - + // check the sub-classes of current class for(int i=0;i<p_class->subclasses.size();i++) { if (p_line>=p_class->subclasses[i]->line && (p_line<=p_class->subclasses[i]->end_line || p_class->subclasses[i]->end_line==-1)) { - + // if OK in sub-classes, try completing the sub-class if (_parse_completion_class(p_base_path,p_class->subclasses[i],p_line,r_options,p_indices)) return true; } @@ -586,7 +843,7 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) { //if in function, first block stuff from outer to inner - if (_parse_completion_block(fu->body,p_line,r_options,p_indices)) + if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices)) return true; //then function arguments if (!p_indices) { @@ -606,7 +863,7 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) { //if in function, first block stuff from outer to inne - if (_parse_completion_block(fu->body,p_line,r_options,p_indices)) + if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices)) return true; //then function arguments if (!p_indices) { @@ -757,24 +1014,30 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_base, List<String>* r_options) { + + GDParser p; Error err = p.parse(p_code,p_base_path); // don't care much about error I guess const GDParser::Node* root = p.get_parse_tree(); ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA); + print_line("BASE: "+p_base); const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); List<String> indices; Vector<String> spl = p_base.split("."); for(int i=0;i<spl.size()-1;i++) { + print_line("INDEX "+itos(i)+": "+spl[i]); indices.push_back(spl[i]); } + //parse completion inside of the class first if (_parse_completion_class(p_base,cl,p_line,r_options,indices.front())) return OK; - //and the globals x_x? + + //if parsing completion inside of the class fails (none found), try using globals for completion for(Map<StringName,int>::Element *E=globals.front();E;E=E->next()) { if (!indices.empty()) { if (String(E->key())==indices.front()->get()) { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index de2b5219a..904b6ba52 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -225,7 +225,14 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ String path = tokenizer->get_token_constant(); if (!path.is_abs_path() && base_path!="") path=base_path+"/"+path; - path = path.replace("///","//"); + path = path.replace("///","//").simplify_path(); + if (path==self_path) { + + _set_error("Can't preload itself (use 'get_script()')."); + return NULL; + + } + Ref<Resource> res; if (!validating) { @@ -2616,8 +2623,9 @@ Error GDParser::_parse(const String& p_base_path) { return OK; } -Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path) { +Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) { + self_path=p_self_path; GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer ); tb->set_code_buffer(p_bytecode); tokenizer=tb; @@ -2628,9 +2636,9 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p } -Error GDParser::parse(const String& p_code,const String& p_base_path,bool p_just_validate) { - +Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) { + self_path=p_self_path; GDTokenizerText *tt = memnew( GDTokenizerText ); tt->set_code(p_code); diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 5fac34396..3f82cafc6 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -373,6 +373,7 @@ private: List<int> tab_level; String base_path; + String self_path; PropertyInfo current_export; @@ -398,8 +399,8 @@ public: String get_error() const; int get_error_line() const; int get_error_column() const; - Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false); - Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path=""); + Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path=""); + Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="",const String& p_self_path=""); const Node *get_parse_tree() const; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 7085ae6a5..982584c75 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1523,6 +1523,7 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { placeholders.erase(p_placeholder); } +/* void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { @@ -1563,7 +1564,7 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { p_placeholder->update(plist,default_values); -} +}*/ #endif ScriptInstance* GDScript::instance_create(Object *p_this) { @@ -1582,7 +1583,8 @@ ScriptInstance* GDScript::instance_create(Object *p_this) { }*/ PlaceHolderScriptInstance *si = memnew( PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(),Ref<Script>(this),p_this) ); placeholders.insert(si); - _update_placeholder(si); + //_update_placeholder(si); + _update_exports(); return si; #else return NULL; @@ -1623,61 +1625,136 @@ String GDScript::get_source_code() const { } void GDScript::set_source_code(const String& p_code) { + if (source==p_code) + return; source=p_code; +#ifdef TOOLS_ENABLED + source_changed_cache=true; + //print_line("SC CHANGED "+get_path()); +#endif + } +#ifdef TOOLS_ENABLED +void GDScript::_update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames) { + + if (base_cache.is_valid()) { + base_cache->_update_exports_values(values,propnames); + } + + for(Map<StringName,Variant>::Element *E=member_default_values_cache.front();E;E=E->next()) { + values[E->key()]=E->get(); + } + + for (List<PropertyInfo>::Element *E=members_cache.front();E;E=E->next()) { + propnames.push_back(E->get()); + } + +} +#endif -void GDScript::_update_exports(Set<PlaceHolderScriptInstance*> *p_instances) { +bool GDScript::_update_exports() { #ifdef TOOLS_ENABLED - String basedir=path; + bool changed=false; - if (basedir=="") - basedir=get_path(); + if (source_changed_cache) { + //print_line("updating source for "+get_path()); + source_changed_cache=false; + changed=true; - if (basedir!="") - basedir=basedir.get_base_dir(); + String basedir=path; - GDParser parser; - Error err = parser.parse(source,basedir,true); - if (err) - return; //do none + if (basedir=="") + basedir=get_path(); - const GDParser::Node* root = parser.get_parse_tree(); - ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS); + if (basedir!="") + basedir=basedir.get_base_dir(); + GDParser parser; + Error err = parser.parse(source,basedir,true,path); + if (err==OK) { - const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root); + const GDParser::Node* root = parser.get_parse_tree(); + ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,false); - if (c->extends_used && String(c->extends_file)!="") { + const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root); - Ref<GDScript> bf = ResourceLoader::load(c->extends_file); - if (bf.is_valid()) { + if (base_cache.is_valid()) { + base_cache->inheriters_cache.erase(get_instance_ID()); + base_cache=Ref<GDScript>(); + } - bf->_update_exports(p_instances); - } - } + if (c->extends_used && String(c->extends_file)!="") { - List<PropertyInfo> plist; + String path = c->extends_file; + if (path.is_rel_path()) { - Map<StringName,Variant> default_values; + String base = get_path(); + if (base=="" || base.is_rel_path()) { - for(int i=0;i<c->variables.size();i++) { - if (c->variables[i]._export.type==Variant::NIL) - continue; + ERR_PRINT(("Could not resolve relative path for parent class: "+path).utf8().get_data()); + } else { + path=base.get_base_dir().plus_file(path); + } + } + + Ref<GDScript> bf = ResourceLoader::load(path); + + if (bf.is_valid()) { + + //print_line("parent is: "+bf->get_path()); + base_cache=bf; + bf->inheriters_cache.insert(get_instance_ID()); + + //bf->_update_exports(p_instances,true,false); + + } + } + + members_cache.clear();; + member_default_values_cache.clear(); + + for(int i=0;i<c->variables.size();i++) { + if (c->variables[i]._export.type==Variant::NIL) + continue; + + members_cache.push_back(c->variables[i]._export); + //print_line("found "+c->variables[i]._export.name); + member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value; + } + } + } else { + //print_line("unchaged is "+get_path()); - plist.push_back(c->variables[i]._export); - default_values[c->variables[i].identifier]=c->variables[i].default_value; } + if (base_cache.is_valid()) { + if (base_cache->_update_exports()) { + changed = true; + } + } - for (Set<PlaceHolderScriptInstance*>::Element *E=p_instances->front();E;E=E->next()) { + if (/*changed &&*/ placeholders.size()) { //hm :( - E->get()->update(plist,default_values); + //print_line("updating placeholders for "+get_path()); + + //update placeholders if any + Map<StringName,Variant> values; + List<PropertyInfo> propnames; + _update_exports_values(values,propnames); + + for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + + E->get()->update(propnames,values); + } } + + return changed; + #endif } @@ -1685,8 +1762,20 @@ void GDScript::update_exports() { #ifdef TOOLS_ENABLED - _update_exports(&placeholders); + _update_exports(); + Set<ObjectID> copy=inheriters_cache; //might get modified + + //print_line("update exports for "+get_path()+" ic: "+itos(copy.size())); + for(Set<ObjectID>::Element *E=copy.front();E;E=E->next()) { + Object *id=ObjectDB::get_instance(E->get()); + if (!id) + continue; + GDScript *s=id->cast_to<GDScript>(); + if (!s) + continue; + s->update_exports(); + } #endif } @@ -1718,7 +1807,7 @@ Error GDScript::reload() { valid=false; GDParser parser; - Error err = parser.parse(source,basedir); + Error err = parser.parse(source,basedir,false,path); if (err) { if (ScriptDebugger::get_singleton()) { GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error()); @@ -1746,10 +1835,10 @@ Error GDScript::reload() { } #ifdef TOOLS_ENABLED - for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + /*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { _update_placeholder(E->get()); - } + }*/ #endif return OK; } @@ -1892,7 +1981,7 @@ Error GDScript::load_byte_code(const String& p_path) { valid=false; GDParser parser; - Error err = parser.parse_bytecode(bytecode,basedir); + Error err = parser.parse_bytecode(bytecode,basedir,get_path()); if (err) { _err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data()); ERR_FAIL_V(ERR_PARSE_ERROR); @@ -1945,6 +2034,10 @@ Error GDScript::load_source_code(const String& p_path) { } source=s; +#ifdef TOOLS_ENABLED + source_changed_cache=true; +#endif + //print_line("LSC :"+get_path()); path=p_path; return OK; @@ -1986,6 +2079,9 @@ GDScript::GDScript() { _base=NULL; _owner=NULL; tool=false; +#ifdef TOOLS_ENABLED + source_changed_cache=false; +#endif } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 3b183a41b..f4e4dffaa 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -245,7 +245,16 @@ friend class GDScriptLanguage; Map<StringName,Ref<GDScript> > subclasses; #ifdef TOOLS_ENABLED + Map<StringName,Variant> member_default_values; + + List<PropertyInfo> members_cache; + Map<StringName,Variant> member_default_values_cache; + Ref<GDScript> base_cache; + Set<ObjectID> inheriters_cache; + bool source_changed_cache; + void _update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames); + #endif Map<StringName,PropertyInfo> member_info; @@ -265,13 +274,13 @@ friend class GDScriptLanguage; #ifdef TOOLS_ENABLED Set<PlaceHolderScriptInstance*> placeholders; - void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); #endif - void _update_exports(Set<PlaceHolderScriptInstance *> *p_instances); + bool _update_exports(); protected: bool _get(const StringName& p_name,Variant &r_ret) const; |
