- added 'onready' keyword to gdscript. Defers initialization of member variables until _ready() is run.
This commit is contained in:
parent
eecfeb1d76
commit
30c12297dc
|
@ -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;
|
Vector<int> bytecode;
|
||||||
CodeGen codegen;
|
CodeGen codegen;
|
||||||
|
@ -1212,9 +1212,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
|
||||||
|
|
||||||
/* Parse initializer -if applies- */
|
/* 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
|
//parse initializer for class members
|
||||||
if (!p_func && p_class->extends_used && p_script->native.is_null()){
|
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- */
|
/* Parse default argument code -if applies- */
|
||||||
|
|
||||||
Vector<int> defarg_addr;
|
Vector<int> defarg_addr;
|
||||||
|
@ -1260,7 +1271,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
|
||||||
|
|
||||||
func_name=p_func->name;
|
func_name=p_func->name;
|
||||||
} else {
|
} else {
|
||||||
func_name="_init";
|
if (p_for_ready)
|
||||||
|
func_name="_ready";
|
||||||
|
else
|
||||||
|
func_name="_init";
|
||||||
}
|
}
|
||||||
|
|
||||||
codegen.opcodes.push_back(GDFunction::OPCODE_END);
|
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
|
//parse methods
|
||||||
|
|
||||||
bool has_initializer=false;
|
bool has_initializer=false;
|
||||||
|
bool has_ready=false;
|
||||||
|
|
||||||
for(int i=0;i<p_class->functions.size();i++) {
|
for(int i=0;i<p_class->functions.size();i++) {
|
||||||
|
|
||||||
if (!has_initializer && p_class->functions[i]->name=="_init")
|
if (!has_initializer && p_class->functions[i]->name=="_init")
|
||||||
has_initializer=true;
|
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]);
|
Error err = _parse_function(p_script,p_class,p_class->functions[i]);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -1640,6 +1658,13 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
|
||||||
return err;
|
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
|
#ifdef DEBUG_ENABLED
|
||||||
//validate setters/getters if debug is enabled
|
//validate setters/getters if debug is enabled
|
||||||
for(int i=0;i<p_class->variables.size();i++) {
|
for(int i=0;i<p_class->variables.size();i++) {
|
||||||
|
|
|
@ -143,7 +143,7 @@ class GDCompiler {
|
||||||
int _parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level);
|
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);
|
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_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);
|
Error _parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class);
|
||||||
int err_line;
|
int err_line;
|
||||||
int err_column;
|
int err_column;
|
||||||
|
|
|
@ -2767,6 +2767,21 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}; //fallthrough to var
|
}; //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: {
|
case GDTokenizer::TK_PR_VAR: {
|
||||||
//variale declaration and (eventual) initialization
|
//variale declaration and (eventual) initialization
|
||||||
|
|
||||||
|
@ -2777,6 +2792,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
||||||
current_export=PropertyInfo();
|
current_export=PropertyInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool onready = tokenizer->get_token(-1)==GDTokenizer::TK_PR_ONREADY;
|
||||||
|
|
||||||
tokenizer->advance();
|
tokenizer->advance();
|
||||||
if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
|
if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
|
||||||
|
|
||||||
|
@ -2807,6 +2824,21 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
||||||
return;
|
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;
|
member.expression=subexpr;
|
||||||
|
|
||||||
if (autoexport) {
|
if (autoexport) {
|
||||||
|
@ -2853,12 +2885,19 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
||||||
op->arguments.push_back(id);
|
op->arguments.push_back(id);
|
||||||
op->arguments.push_back(subexpr);
|
op->arguments.push_back(subexpr);
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
NewLineNode *nl = alloc_node<NewLineNode>();
|
NewLineNode *nl = alloc_node<NewLineNode>();
|
||||||
nl->line=line;
|
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
|
#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>();
|
ClassNode *main_class = alloc_node<ClassNode>();
|
||||||
main_class->initializer = alloc_node<BlockNode>();
|
main_class->initializer = alloc_node<BlockNode>();
|
||||||
main_class->initializer->parent_class=main_class;
|
main_class->initializer->parent_class=main_class;
|
||||||
|
main_class->ready = alloc_node<BlockNode>();
|
||||||
|
main_class->ready->parent_class=main_class;
|
||||||
current_class=main_class;
|
current_class=main_class;
|
||||||
|
|
||||||
_parse_class(main_class);
|
_parse_class(main_class);
|
||||||
|
|
|
@ -105,6 +105,7 @@ public:
|
||||||
Vector<FunctionNode*> static_functions;
|
Vector<FunctionNode*> static_functions;
|
||||||
Vector<Signal> _signals;
|
Vector<Signal> _signals;
|
||||||
BlockNode *initializer;
|
BlockNode *initializer;
|
||||||
|
BlockNode *ready;
|
||||||
ClassNode *owner;
|
ClassNode *owner;
|
||||||
//Vector<Node*> initializers;
|
//Vector<Node*> initializers;
|
||||||
int end_line;
|
int end_line;
|
||||||
|
|
|
@ -2652,6 +2652,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
|
||||||
"elif",
|
"elif",
|
||||||
"enum",
|
"enum",
|
||||||
"extends" ,
|
"extends" ,
|
||||||
|
"onready",
|
||||||
"for" ,
|
"for" ,
|
||||||
"func" ,
|
"func" ,
|
||||||
"if" ,
|
"if" ,
|
||||||
|
|
|
@ -851,6 +851,7 @@ void GDTokenizerText::_advance() {
|
||||||
{TK_PR_FUNCTION,"function"},
|
{TK_PR_FUNCTION,"function"},
|
||||||
{TK_PR_CLASS,"class"},
|
{TK_PR_CLASS,"class"},
|
||||||
{TK_PR_EXTENDS,"extends"},
|
{TK_PR_EXTENDS,"extends"},
|
||||||
|
{TK_PR_ONREADY,"onready"},
|
||||||
{TK_PR_TOOL,"tool"},
|
{TK_PR_TOOL,"tool"},
|
||||||
{TK_PR_STATIC,"static"},
|
{TK_PR_STATIC,"static"},
|
||||||
{TK_PR_EXPORT,"export"},
|
{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) {
|
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
TK_PR_FUNCTION,
|
TK_PR_FUNCTION,
|
||||||
TK_PR_CLASS,
|
TK_PR_CLASS,
|
||||||
TK_PR_EXTENDS,
|
TK_PR_EXTENDS,
|
||||||
|
TK_PR_ONREADY,
|
||||||
TK_PR_TOOL,
|
TK_PR_TOOL,
|
||||||
TK_PR_STATIC,
|
TK_PR_STATIC,
|
||||||
TK_PR_EXPORT,
|
TK_PR_EXPORT,
|
||||||
|
|
Loading…
Reference in New Issue