summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2015-12-28 19:31:52 -0300
committerreduz <reduzio@gmail.com>2015-12-28 19:32:51 -0300
commit30c12297dc6df7d35df140475c0cec7308aea77a (patch)
treee09c1ed46a6d42bcaab5ff4f3a67749948ff6ff7
parenteecfeb1d7681bf9186bc231e9ee8c5d36f2afcea (diff)
- added 'onready' keyword to gdscript. Defers initialization of member variables until _ready() is run.
-rw-r--r--modules/gdscript/gd_compiler.cpp33
-rw-r--r--modules/gdscript/gd_compiler.h2
-rw-r--r--modules/gdscript/gd_parser.cpp45
-rw-r--r--modules/gdscript/gd_parser.h1
-rw-r--r--modules/gdscript/gd_script.cpp1
-rw-r--r--modules/gdscript/gd_tokenizer.cpp3
-rw-r--r--modules/gdscript/gd_tokenizer.h1
7 files changed, 78 insertions, 8 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index a62225f663..a45c79aca7 100644
--- a/modules/gdscript/gd_compiler.cpp
+++ b/modules/gdscript/gd_compiler.cpp
@@ -1181,7 +1181,7 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
}
-Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func) {
+Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func,bool p_for_ready) {
Vector<int> bytecode;
CodeGen codegen;
@@ -1212,9 +1212,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
/* Parse initializer -if applies- */
- bool is_initializer=false || !p_func;
+ bool is_initializer=!p_for_ready && !p_func;
- if (!p_func || String(p_func->name)=="_init") {
+ if (is_initializer || String(p_func->name)=="_init") {
//parse initializer for class members
if (!p_func && p_class->extends_used && p_script->native.is_null()){
@@ -1232,6 +1232,17 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
}
+ if (p_for_ready || (p_func && String(p_func->name)=="_ready")) {
+ //parse initializer for class members
+ if (p_class->ready->statements.size()) {
+ Error err = _parse_block(codegen,p_class->ready,stack_level);
+ if (err)
+ return err;
+ }
+
+ }
+
+
/* Parse default argument code -if applies- */
Vector<int> defarg_addr;
@@ -1260,7 +1271,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
func_name=p_func->name;
} else {
- func_name="_init";
+ if (p_for_ready)
+ func_name="_ready";
+ else
+ func_name="_init";
}
codegen.opcodes.push_back(GDFunction::OPCODE_END);
@@ -1614,10 +1628,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
//parse methods
bool has_initializer=false;
+ bool has_ready=false;
+
for(int i=0;i<p_class->functions.size();i++) {
if (!has_initializer && p_class->functions[i]->name=="_init")
has_initializer=true;
+ if (!has_ready && p_class->functions[i]->name=="_ready")
+ has_ready=true;
Error err = _parse_function(p_script,p_class,p_class->functions[i]);
if (err)
return err;
@@ -1640,6 +1658,13 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
return err;
}
+ if (!has_ready && p_class->ready->statements.size()) {
+ //create a constructor
+ Error err = _parse_function(p_script,p_class,NULL,true);
+ if (err)
+ return err;
+ }
+
#ifdef DEBUG_ENABLED
//validate setters/getters if debug is enabled
for(int i=0;i<p_class->variables.size();i++) {
diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h
index bdf4e9816a..ea3e7c8b69 100644
--- a/modules/gdscript/gd_compiler.h
+++ b/modules/gdscript/gd_compiler.h
@@ -143,7 +143,7 @@ class GDCompiler {
int _parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level);
int _parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root=false,bool p_initializer=false);
Error _parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level=0,int p_break_addr=-1,int p_continue_addr=-1);
- Error _parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func);
+ Error _parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func,bool p_for_ready=false);
Error _parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class);
int err_line;
int err_column;
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 4339a13edf..95e172e26e 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -2767,6 +2767,21 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
}; //fallthrough to var
+ case GDTokenizer::TK_PR_ONREADY: {
+
+ if (tokenizer->get_token(-1)==GDTokenizer::TK_PR_EXPORT) {
+ current_export=PropertyInfo();
+ _set_error("Expected 'var' (can't combine with 'onready').");
+ return;
+ } else {
+
+ tokenizer->advance();
+ if (tokenizer->get_token()!=GDTokenizer::TK_PR_VAR) {
+ _set_error("Expected 'var'.");
+ return;
+ }
+ }
+ }; //fallthrough to var
case GDTokenizer::TK_PR_VAR: {
//variale declaration and (eventual) initialization
@@ -2777,6 +2792,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
}
+ bool onready = tokenizer->get_token(-1)==GDTokenizer::TK_PR_ONREADY;
+
tokenizer->advance();
if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
@@ -2807,6 +2824,21 @@ void GDParser::_parse_class(ClassNode *p_class) {
return;
}
+ //discourage common error
+ if (!onready && subexpr->type==Node::TYPE_OPERATOR) {
+
+ OperatorNode *op=static_cast<OperatorNode*>(subexpr);
+ if (op->op==OperatorNode::OP_CALL && op->arguments[0]->type==Node::TYPE_SELF && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+ IdentifierNode *id=static_cast<IdentifierNode*>(op->arguments[1]);
+ if (id->name=="get_node") {
+
+ _set_error("Use 'onready var "+String(member.identifier)+" = get_node(..)' instead");
+ return;
+
+ }
+ }
+ }
+
member.expression=subexpr;
if (autoexport) {
@@ -2853,12 +2885,19 @@ void GDParser::_parse_class(ClassNode *p_class) {
op->arguments.push_back(id);
op->arguments.push_back(subexpr);
+
#ifdef DEBUG_ENABLED
NewLineNode *nl = alloc_node<NewLineNode>();
nl->line=line;
- p_class->initializer->statements.push_back(nl);
+ if (onready)
+ p_class->ready->statements.push_back(nl);
+ else
+ p_class->initializer->statements.push_back(nl);
#endif
- p_class->initializer->statements.push_back(op);
+ if (onready)
+ p_class->ready->statements.push_back(op);
+ else
+ p_class->initializer->statements.push_back(op);
@@ -3009,6 +3048,8 @@ Error GDParser::_parse(const String& p_base_path) {
ClassNode *main_class = alloc_node<ClassNode>();
main_class->initializer = alloc_node<BlockNode>();
main_class->initializer->parent_class=main_class;
+ main_class->ready = alloc_node<BlockNode>();
+ main_class->ready->parent_class=main_class;
current_class=main_class;
_parse_class(main_class);
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index 04f3dff3de..4aa5c8cfea 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -105,6 +105,7 @@ public:
Vector<FunctionNode*> static_functions;
Vector<Signal> _signals;
BlockNode *initializer;
+ BlockNode *ready;
ClassNode *owner;
//Vector<Node*> initializers;
int end_line;
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index ef53dcfe71..70c7887766 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -2652,6 +2652,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"elif",
"enum",
"extends" ,
+ "onready",
"for" ,
"func" ,
"if" ,
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index e445701669..c732c00b82 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -851,6 +851,7 @@ void GDTokenizerText::_advance() {
{TK_PR_FUNCTION,"function"},
{TK_PR_CLASS,"class"},
{TK_PR_EXTENDS,"extends"},
+ {TK_PR_ONREADY,"onready"},
{TK_PR_TOOL,"tool"},
{TK_PR_STATIC,"static"},
{TK_PR_EXPORT,"export"},
@@ -1040,7 +1041,7 @@ void GDTokenizerText::advance(int p_amount) {
//////////////////////////////////////////////////////////////////////////////////////////////////////
-#define BYTECODE_VERSION 5
+#define BYTECODE_VERSION 6
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 d6bd63c5b8..3c0107cea2 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -95,6 +95,7 @@ public:
TK_PR_FUNCTION,
TK_PR_CLASS,
TK_PR_EXTENDS,
+ TK_PR_ONREADY,
TK_PR_TOOL,
TK_PR_STATIC,
TK_PR_EXPORT,