|
@@ -75,20 +75,28 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
|
|
|
|
|
|
if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) {
|
|
|
|
|
|
- _set_error("newline expected after ':'.");
|
|
|
- return false;
|
|
|
+ // be more python-like
|
|
|
+ int current = tab_level.back()->get();
|
|
|
+ tab_level.push_back(current+1);
|
|
|
+ return true;
|
|
|
+ //_set_error("newline expected after ':'.");
|
|
|
+ //return false;
|
|
|
}
|
|
|
|
|
|
while(true) {
|
|
|
|
|
|
if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) {
|
|
|
+ print_line("no newline");
|
|
|
return false; //wtf
|
|
|
} else if (tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE) {
|
|
|
|
|
|
int indent = tokenizer->get_token_line_indent();
|
|
|
int current = tab_level.back()->get();
|
|
|
- if (indent<=current)
|
|
|
+ if (indent<=current) {
|
|
|
+ print_line("current: "+itos(current)+" indent: "+itos(indent));
|
|
|
+ print_line("less than current");
|
|
|
return false;
|
|
|
+ }
|
|
|
|
|
|
tab_level.push_back(indent);
|
|
|
tokenizer->advance();
|
|
@@ -1588,6 +1596,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
p_block->sub_blocks.push_back(cf_if->body);
|
|
|
|
|
|
if (!_enter_indent_block(cf_if->body)) {
|
|
|
+ _set_error("Expected intended block after 'if'");
|
|
|
p_block->end_line=tokenizer->get_token_line();
|
|
|
return;
|
|
|
}
|
|
@@ -1647,6 +1656,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
|
|
|
|
|
|
if (!_enter_indent_block(cf_if->body)) {
|
|
|
+ _set_error("Expected indented block after 'elif'");
|
|
|
p_block->end_line=tokenizer->get_token_line();
|
|
|
return;
|
|
|
}
|
|
@@ -1661,7 +1671,6 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
} else if (tokenizer->get_token()==GDTokenizer::TK_CF_ELSE) {
|
|
|
|
|
|
if (tab_level.back()->get() > indent_level) {
|
|
|
-
|
|
|
_set_error("Invalid indent");
|
|
|
return;
|
|
|
}
|
|
@@ -1673,6 +1682,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
p_block->sub_blocks.push_back(cf_if->body_else);
|
|
|
|
|
|
if (!_enter_indent_block(cf_if->body_else)) {
|
|
|
+ _set_error("Expected indented block after 'else'");
|
|
|
p_block->end_line=tokenizer->get_token_line();
|
|
|
return;
|
|
|
}
|
|
@@ -1713,6 +1723,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
p_block->sub_blocks.push_back(cf_while->body);
|
|
|
|
|
|
if (!_enter_indent_block(cf_while->body)) {
|
|
|
+ _set_error("Expected indented block after 'while'");
|
|
|
p_block->end_line=tokenizer->get_token_line();
|
|
|
return;
|
|
|
}
|
|
@@ -1764,6 +1775,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
p_block->sub_blocks.push_back(cf_for->body);
|
|
|
|
|
|
if (!_enter_indent_block(cf_for->body)) {
|
|
|
+ _set_error("Expected indented block after 'while'");
|
|
|
p_block->end_line=tokenizer->get_token_line();
|
|
|
return;
|
|
|
}
|
|
@@ -1850,6 +1862,17 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|
|
return;
|
|
|
}
|
|
|
} break;
|
|
|
+ case GDTokenizer::TK_PR_BREAKPOINT: {
|
|
|
+
|
|
|
+ tokenizer->advance();
|
|
|
+ BreakpointNode *bn = alloc_node<BreakpointNode>();
|
|
|
+ p_block->statements.push_back(bn);
|
|
|
+
|
|
|
+ if (!_end_statement()) {
|
|
|
+ _set_error("Expected end of statement after breakpoint.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } break;
|
|
|
default: {
|
|
|
|
|
|
Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true);
|
|
@@ -2058,6 +2081,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|
|
ClassNode *newclass = alloc_node<ClassNode>();
|
|
|
newclass->initializer = alloc_node<BlockNode>();
|
|
|
newclass->initializer->parent_class=newclass;
|
|
|
+ newclass->ready = alloc_node<BlockNode>();
|
|
|
+ newclass->ready->parent_class=newclass;
|
|
|
newclass->name=name;
|
|
|
newclass->owner=p_class;
|
|
|
|
|
@@ -2767,6 +2792,17 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|
|
}
|
|
|
|
|
|
}; //fallthrough to var
|
|
|
+ case GDTokenizer::TK_PR_ONREADY: {
|
|
|
+
|
|
|
+ if (token==GDTokenizer::TK_PR_ONREADY) {
|
|
|
+ //may be fallthrough from export, ignore if so
|
|
|
+ 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 +2813,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 +2845,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 +2906,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 +3069,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);
|