diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gd_compiler.cpp | 10 | ||||
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 155 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gd_script.cpp | 61 | ||||
-rw-r--r-- | modules/gdscript/gd_script.h | 14 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 18 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.h | 1 | ||||
-rw-r--r-- | modules/gdscript/register_types.cpp | 4 |
9 files changed, 195 insertions, 79 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 45eac23450..4c56468297 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -179,7 +179,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre //static function if (codegen.script->member_indices.has(identifier)) { - int idx = codegen.script->member_indices[identifier]; + int idx = codegen.script->member_indices[identifier].index; return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root) } } @@ -1507,8 +1507,12 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars #endif } - int new_idx = p_script->member_indices.size(); - p_script->member_indices[name]=new_idx; + //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; + p_script->member_indices[name]=minfo; p_script->members.insert(name); } diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index a98b07ab92..d1f511b46e 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -114,6 +114,7 @@ int GDScriptLanguage::find_function(const String& p_function,const String& p_cod if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { indent=tokenizer.get_token_line_indent(); } + //print_line("TOKEN: "+String(GDTokenizer::get_token_name(tokenizer.get_token()))); if (indent==0 && tokenizer.get_token()==GDTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1)==GDTokenizer::TK_IDENTIFIER) { String identifier = tokenizer.get_token_identifier(1); @@ -122,6 +123,8 @@ int GDScriptLanguage::find_function(const String& p_function,const String& p_cod } } tokenizer.advance(); + //print_line("NEXT: "+String(GDTokenizer::get_token_name(tokenizer.get_token()))); + } return -1; } @@ -247,12 +250,12 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p ERR_FAIL_COND( script.is_null() ); - const Map<StringName,int>& mi = script->debug_get_member_indices(); + const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices(); - for(const Map<StringName,int>::Element *E=mi.front();E;E=E->next()) { + for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) { p_members->push_back(E->key()); - p_values->push_back( instance->debug_get_member_by_index(E->get())); + p_values->push_back( instance->debug_get_member_by_index(E->get().index)); } } diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 46eade0b7c..659e19a9d0 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -372,10 +372,26 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { //identifier (reference) - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=tokenizer->get_token_identifier(); - tokenizer->advance(); - expr=id; + const ClassNode* cln = static_cast<const ClassNode*>(get_parse_tree()); + bool bfn = false; + StringName idn( tokenizer->get_token_identifier() ); + + for( int i=0; i<cln->constant_expressions.size(); ++i ) { + + if( cln->constant_expressions[i].identifier == idn ) { + tokenizer->advance(); + expr = cln->constant_expressions[i].expression; + bfn = true; + break; + } + } + + if( !bfn ) { + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->name = idn; + tokenizer->advance(); + expr = id; + } } else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) { @@ -1179,7 +1195,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { case OperatorNode::OP_ASSIGN_BIT_XOR: { if (op->arguments[0]->type==Node::TYPE_CONSTANT) { - _set_error("Can't assign to constant"); + _set_error("Can't assign to constant",tokenizer->get_token_line()-1); return op; } @@ -2360,80 +2376,113 @@ void GDParser::_parse_class(ClassNode *p_class) { member._export.name=member.identifier; tokenizer->advance(); - p_class->variables.push_back(member); + if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) { - if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) { +#ifdef DEBUG_ENABLED + int line = tokenizer->get_token_line(); +#endif + tokenizer->advance(); - if (autoexport) { + Node *subexpr=NULL; - _set_error("Type-less export needs a constant expression assigned to infer type."); + subexpr = _parse_and_reduce_expression(p_class,false); + if (!subexpr) return; - } - break; - } -#ifdef DEBUG_ENABLED - int line = tokenizer->get_token_line(); -#endif - tokenizer->advance(); - Node *subexpr=NULL; + if (autoexport) { + if (subexpr->type==Node::TYPE_ARRAY) { - subexpr = _parse_and_reduce_expression(p_class,false); - if (!subexpr) - return; + member._export.type=Variant::ARRAY; - if (autoexport) { - if (subexpr->type==Node::TYPE_ARRAY) { + } else if (subexpr->type==Node::TYPE_DICTIONARY) { - p_class->variables[p_class->variables.size()-1]._export.type=Variant::ARRAY; + member._export.type=Variant::DICTIONARY; - } else if (subexpr->type==Node::TYPE_DICTIONARY) { + } else { - p_class->variables[p_class->variables.size()-1]._export.type=Variant::DICTIONARY; + if (subexpr->type!=Node::TYPE_CONSTANT) { - } else { + _set_error("Type-less export needs a constant expression assigned to infer type."); + return; + } - if (subexpr->type!=Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode*>(subexpr); + if (cn->value.get_type()==Variant::NIL) { - _set_error("Type-less export needs a constant expression assigned to infer type."); - return; + _set_error("Can't accept a null constant expression for infering export type."); + return; + } + member._export.type=cn->value.get_type(); } + } +#ifdef TOOLS_ENABLED + if (subexpr->type==Node::TYPE_CONSTANT && member._export.type!=Variant::NIL) { ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type()==Variant::NIL) { - - _set_error("Can't accept a null constant expression for infering export type."); - return; + if (cn->value.get_type()!=Variant::NIL) { + member.default_value=cn->value; } - p_class->variables[p_class->variables.size()-1]._export.type=cn->value.get_type(); } - } -#ifdef TOOLS_ENABLED - if (subexpr->type==Node::TYPE_CONSTANT && p_class->variables[p_class->variables.size()-1]._export.type!=Variant::NIL) { +#endif + + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->name=member.identifier; + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=OperatorNode::OP_ASSIGN; + op->arguments.push_back(id); + op->arguments.push_back(subexpr); - ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type()!=Variant::NIL) { - p_class->variables[p_class->variables.size()-1].default_value=cn->value; +#ifdef DEBUG_ENABLED + NewLineNode *nl = alloc_node<NewLineNode>(); + nl->line=line; + p_class->initializer->statements.push_back(nl); +#endif + p_class->initializer->statements.push_back(op); + + + + } else { + + if (autoexport) { + + _set_error("Type-less export needs a constant expression assigned to infer type."); + return; } + } -#endif + if (tokenizer->get_token()==GDTokenizer::TK_PR_SETGET) { - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=member.identifier; + tokenizer->advance(); - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_ASSIGN; - op->arguments.push_back(id); - op->arguments.push_back(subexpr); + if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { + //just comma means using only getter + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier for setter function after 'notify'."); + } -#ifdef DEBUG_ENABLED - NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=line; - p_class->initializer->statements.push_back(nl); -#endif - p_class->initializer->statements.push_back(op); + member.setter=tokenizer->get_token_identifier(); + + tokenizer->advance(); + } + + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + //there is a getter + tokenizer->advance(); + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier for getter function after ','."); + } + + member.getter=tokenizer->get_token_identifier(); + tokenizer->advance(); + + } + } + + p_class->variables.push_back(member); _end_statement(); diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 50b84d389a..16a9a85290 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -82,6 +82,8 @@ public: Variant default_value; #endif StringName identifier; + StringName setter; + StringName getter; }; struct Constant { StringName identifier; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 49d92e0746..b20fc51a03 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1537,7 +1537,7 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { _GDScriptMemberSort ms; ERR_CONTINUE(!scr->member_indices.has(E->key())); - ms.index=scr->member_indices[E->key()]; + ms.index=scr->member_indices[E->key()].index; ms.name=E->key(); msort.push_back(ms); @@ -1626,9 +1626,11 @@ void GDScript::set_source_code(const String& p_code) { source=p_code; } -void GDScript::update_exports() { + +void GDScript::_update_exports(Set<PlaceHolderScriptInstance*> *p_instances) { #ifdef TOOLS_ENABLED + String basedir=path; if (basedir=="") @@ -1645,8 +1647,20 @@ void GDScript::update_exports() { const GDParser::Node* root = parser.get_parse_tree(); ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS); + + const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root); + if (c->extends_used && String(c->extends_file)!="") { + + Ref<GDScript> bf = ResourceLoader::load(c->extends_file); + if (bf.is_valid()) { + + bf->_update_exports(p_instances); + + } + } + List<PropertyInfo> plist; Map<StringName,Variant> default_values; @@ -1660,10 +1674,19 @@ void GDScript::update_exports() { } - for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + for (Set<PlaceHolderScriptInstance*>::Element *E=p_instances->front();E;E=E->next()) { E->get()->update(plist,default_values); } +#endif +} + +void GDScript::update_exports() { + +#ifdef TOOLS_ENABLED + + _update_exports(&placeholders); + #endif } @@ -1938,9 +1961,9 @@ const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const { StringName GDScript::debug_get_member_by_index(int p_idx) const { - for(const Map<StringName,int>::Element *E=member_indices.front();E;E=E->next()) { + for(const Map<StringName,MemberInfo>::Element *E=member_indices.front();E;E=E->next()) { - if (E->get()==p_idx) + if (E->get().index==p_idx) return E->key(); } @@ -1979,11 +2002,18 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { //member { - const Map<StringName,int>::Element *E = script->member_indices.find(p_name); + const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { - members[E->get()]=p_value; + members[E->get().index]=p_value; + if (E->get().setter) { + const Variant *val=&p_value; + Variant::CallError err; + call(E->get().setter,&val,1,err); + if (err.error==Variant::CallError::CALL_OK) { + return true; //function exists, call was successful + } + } return true; - } } @@ -2016,9 +2046,16 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const { while(sptr) { { - const Map<StringName,int>::Element *E = script->member_indices.find(p_name); + const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { - r_ret=members[E->get()]; + if (E->get().getter) { + Variant::CallError err; + r_ret=const_cast<GDInstance*>(this)->call(E->get().getter,NULL,0,err); + if (err.error==Variant::CallError::CALL_OK) { + return true; + } + } + r_ret=members[E->get().index]; return true; //index found } @@ -2108,7 +2145,7 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { _GDScriptMemberSort ms; ERR_CONTINUE(!sptr->member_indices.has(E->key())); - ms.index=sptr->member_indices[E->key()]; + ms.index=sptr->member_indices[E->key()].index; ms.name=E->key(); msort.push_back(ms); @@ -2410,7 +2447,6 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "func" , "if" , "in" , - "varl", "null" , "return" , "self" , @@ -2419,6 +2455,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "false" , "tool", "var", + "setget", "pass", "and", "or", diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 2088606271..3b183a41b6 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -220,11 +220,18 @@ class GDScript : public Script { bool valid; + struct MemberInfo { + int index; + StringName setter; + StringName getter; + }; friend class GDInstance; friend class GDFunction; friend class GDCompiler; friend class GDFunctions; +friend class GDScriptLanguage; + Variant _static_ref; //used for static call Ref<GDNativeClass> native; Ref<GDScript> base; @@ -234,7 +241,7 @@ friend class GDFunctions; Set<StringName> members; //members are just indices to the instanced script. Map<StringName,Variant> constants; Map<StringName,GDFunction> member_functions; - Map<StringName,int> member_indices; //members are just indices to the instanced script. + Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script. Map<StringName,Ref<GDScript> > subclasses; #ifdef TOOLS_ENABLED @@ -263,6 +270,9 @@ friend class GDFunctions; #endif + + void _update_exports(Set<PlaceHolderScriptInstance *> *p_instances); + protected: bool _get(const StringName& p_name,Variant &r_ret) const; bool _set(const StringName& p_name, const Variant& p_value); @@ -285,7 +295,7 @@ public: bool is_tool() const { return tool; } Ref<GDScript> get_base() const; - const Map<StringName,int>& debug_get_member_indices() const { return member_indices; } + const Map<StringName,MemberInfo>& debug_get_member_indices() const { return member_indices; } const Map<StringName,GDFunction>& debug_get_member_functions() const; //this is debug only StringName debug_get_member_by_index(int p_idx) const; diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 7a1d6814ba..0fa83b9eb4 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -91,6 +91,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "tool", "static", "export", +"setget", "const", "var", "preload", @@ -237,7 +238,9 @@ void GDTokenizerText::_advance() { while (true) { - bool is_node_path=false; + bool is_node_path = false; + bool is_string = false; + bool is_string_alt = false; switch(GETCHAR(0)) { case 0: @@ -527,13 +530,17 @@ void GDTokenizerText::_advance() { } } break; case '@': - if (CharType(GETCHAR(1))!='"') { + if( CharType(GETCHAR(1))!='"' && CharType(GETCHAR(1))!='\'' ) { _make_error("Unexpected '@'"); return; } INCPOS(1); is_node_path=true; + + case '\'': + is_string_alt = true; case '"': { + is_string = is_string_alt ? false : true; int i=1; String str; @@ -542,8 +549,10 @@ void GDTokenizerText::_advance() { _make_error("Unterminated String"); return; - } else if (CharType(GETCHAR(i)=='"')) { + } else if( CharType(GETCHAR(i)=='"') && is_string ) { break; + } else if( CharType(GETCHAR(i)=='\'') && is_string_alt ) { + break; } else if (CharType(GETCHAR(i)=='\\')) { //escaped characters... i++; @@ -823,6 +832,7 @@ void GDTokenizerText::_advance() { {TK_PR_TOOL,"tool"}, {TK_PR_STATIC,"static"}, {TK_PR_EXPORT,"export"}, + {TK_PR_SETGET,"setget"}, {TK_PR_VAR,"var"}, {TK_PR_PRELOAD,"preload"}, {TK_PR_ASSERT,"assert"}, @@ -1007,7 +1017,7 @@ void GDTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 2 +#define BYTECODE_VERSION 3 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index 1dd538867e..4f9522fb56 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -98,6 +98,7 @@ public: TK_PR_TOOL, TK_PR_STATIC, TK_PR_EXPORT, + TK_PR_SETGET, TK_PR_CONST, TK_PR_VAR, TK_PR_PRELOAD, diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 8b46773502..543eecdf8b 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -121,16 +121,16 @@ static void register_editor_plugin() { void register_gdscript_types() { + ObjectTypeDB::register_type<GDScript>(); + ObjectTypeDB::register_virtual_type<GDFunctionState>(); script_language_gd=memnew( GDScriptLanguage ); script_language_gd->init(); ScriptServer::register_language(script_language_gd); - ObjectTypeDB::register_type<GDScript>(); resource_loader_gd=memnew( ResourceFormatLoaderGDScript ); ResourceLoader::add_resource_format_loader(resource_loader_gd); resource_saver_gd=memnew( ResourceFormatSaverGDScript ); ResourceSaver::add_resource_format_saver(resource_saver_gd); - ObjectTypeDB::register_virtual_type<GDFunctionState>(); #ifdef TOOLS_ENABLED |