diff options
author | Juan Linietsky <reduzio@gmail.com> | 2015-06-24 13:29:23 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2015-06-24 13:29:45 -0300 |
commit | 48f1d02da4795ba9d485fe5fe2bea907be2fc467 (patch) | |
tree | ae248e1e863bb675026c2cfb8399ac8d23f33ed0 /modules | |
parent | 199ad16bbc50d41aaeb76c276947156dafc81481 (diff) |
added ability to define signals in script
closes #2175
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gd_compiler.cpp | 40 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 71 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.h | 7 | ||||
-rw-r--r-- | modules/gdscript/gd_script.cpp | 48 | ||||
-rw-r--r-- | modules/gdscript/gd_script.h | 4 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 1 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.h | 1 |
7 files changed, 154 insertions, 18 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index b405555ec6..a62225f663 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -28,15 +28,6 @@ /*************************************************************************/ #include "gd_compiler.h" #include "gd_script.h" -/* TODO: - - *AND and OR need early abort - -Inheritance properly process (done?) - *create built in initializer and constructor - *assign operators - *build arrays and dictionaries - *call parent constructor - */ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) { @@ -1397,13 +1388,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars int index_from=0; + Ref<GDNativeClass> native; if (p_class->extends_used) { //do inheritance String path = p_class->extends_file; Ref<GDScript> script; - Ref<GDNativeClass> native; + if (path!="") { //path (and optionally subclasses) @@ -1573,7 +1565,35 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars //p_script->constants[constant->value].make_const(); } + for(int i=0;i<p_class->_signals.size();i++) { + + StringName name = p_class->_signals[i].name; + + GDScript *c = p_script; + while(c) { + + if (c->_signals.has(name)) { + _set_error("Signal '"+name+"' redefined (in current or parent class)",p_class); + return ERR_ALREADY_EXISTS; + } + + if (c->base.is_valid()) { + c=c->base.ptr(); + } else { + c=NULL; + } + } + + if (native.is_valid()) { + if (ObjectTypeDB::has_signal(native->get_name(),name)) { + _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class); + return ERR_ALREADY_EXISTS; + } + } + + p_script->_signals[name]=p_class->_signals[i].arguments; + } //parse sub-classes for(int i=0;i<p_class->subclasses.size();i++) { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 6242400663..71af9ab10d 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -1520,8 +1520,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { op->arguments.push_back(assigned); p_block->statements.push_back(op); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (var)"); + return; + } } break; case GDTokenizer::TK_CF_IF: { @@ -1946,8 +1948,10 @@ void GDParser::_parse_class(ClassNode *p_class) { _parse_extends(p_class); if (error_set) return; - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement after extends"); + return; + } } break; case GDTokenizer::TK_PR_TOOL: { @@ -2227,6 +2231,53 @@ void GDParser::_parse_class(ClassNode *p_class) { //arguments } break; + case GDTokenizer::TK_PR_SIGNAL: { + tokenizer->advance(); + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier after 'signal'."); + return; + } + + ClassNode::Signal sig; + sig.name = tokenizer->get_token_identifier(); + tokenizer->advance(); + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + tokenizer->advance(); + while(true) { + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier in signal argument."); + return; + } + + sig.arguments.push_back(tokenizer->get_token_identifier()); + tokenizer->advance(); + + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ',' or ')' after signal parameter identifier."); + return; + } + } + } + + p_class->_signals.push_back(sig); + + if (!_end_statement()) { + _set_error("Expected end of statement (signal)"); + return; + } + } break; case GDTokenizer::TK_PR_EXPORT: { tokenizer->advance(); @@ -2644,8 +2695,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (continue)"); + return; + } } break; case GDTokenizer::TK_PR_CONST: { //variale declaration and (eventual) initialization @@ -2682,8 +2735,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.push_back(constant); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (constant)"); + return; + } } break; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index bf2c8c9ef2..fd5c0802ea 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -76,6 +76,7 @@ public: StringName extends_file; Vector<StringName> extends_class; + struct Member { PropertyInfo _export; #ifdef TOOLS_ENABLED @@ -92,11 +93,17 @@ public: Node *expression; }; + struct Signal { + StringName name; + Vector<StringName> arguments; + }; + Vector<ClassNode*> subclasses; Vector<Member> variables; Vector<Constant> constant_expressions; Vector<FunctionNode*> functions; Vector<FunctionNode*> static_functions; + Vector<Signal> _signals; BlockNode *initializer; ClassNode *owner; //Vector<Node*> initializers; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 70a5fd985c..b6ad7aa716 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1756,6 +1756,12 @@ bool GDScript::_update_exports() { //print_line("found "+c->variables[i]._export.name); member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value; } + + _signals.clear(); + + for(int i=0;i<c->_signals.size();i++) { + _signals[c->_signals[i].name]=c->_signals[i].arguments; + } } } else { //print_line("unchaged is "+get_path()); @@ -2100,6 +2106,47 @@ Ref<GDScript> GDScript::get_base() const { return base; } +bool GDScript::has_script_signal(const StringName& p_signal) const { + if (_signals.has(p_signal)) + return true; + if (base.is_valid()) { + return base->has_script_signal(p_signal); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + return base_cache->has_script_signal(p_signal); + } + +#endif + return false; +} +void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + + for(const Map<StringName,Vector<StringName> >::Element *E=_signals.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get().size();i++) { + PropertyInfo arg; + arg.name=E->get()[i]; + mi.arguments.push_back(arg); + } + r_signals->push_back(mi); + } + + if (base.is_valid()) { + base->get_script_signal_list(r_signals); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + base_cache->get_script_signal_list(r_signals); + } + +#endif + +} + + GDScript::GDScript() { @@ -2594,6 +2641,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "static", "float", "int", + "signal", 0}; diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index f505d51ba4..4672f3b8be 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -260,6 +260,7 @@ friend class GDScriptLanguage; Map<StringName,GDFunction> member_functions; Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script. Map<StringName,Ref<GDScript> > subclasses; + Map<StringName,Vector<StringName> > _signals; #ifdef TOOLS_ENABLED @@ -318,6 +319,9 @@ public: const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; } const Ref<GDNativeClass>& get_native() const { return native; } + virtual bool has_script_signal(const StringName& p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + bool is_tool() const { return tool; } Ref<GDScript> get_base() const; diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 0745baafe6..656a015c66 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -856,6 +856,7 @@ void GDTokenizerText::_advance() { {TK_PR_PRELOAD,"preload"}, {TK_PR_ASSERT,"assert"}, {TK_PR_YIELD,"yield"}, + {TK_PR_SIGNAL,"signal"}, {TK_PR_CONST,"const"}, //controlflow {TK_CF_IF,"if"}, diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index b63687d2b4..d6bd63c5b8 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -104,6 +104,7 @@ public: TK_PR_PRELOAD, TK_PR_ASSERT, TK_PR_YIELD, + TK_PR_SIGNAL, TK_BRACKET_OPEN, TK_BRACKET_CLOSE, TK_CURLY_BRACKET_OPEN, |