Browse Source

detect node and variable assignments in _ready, _init, etc for further code completion

Juan Linietsky 10 years ago
parent
commit
319cc7e3ae
3 changed files with 127 additions and 11 deletions
  1. 53 1
      modules/gdscript/gd_editor.cpp
  2. 72 10
      modules/gdscript/gd_parser.cpp
  3. 2 0
      modules/gdscript/gd_parser.h

+ 53 - 1
modules/gdscript/gd_editor.cpp

@@ -998,6 +998,44 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l
 	return false;
 	return false;
 }
 }
 
 
+
+static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context,const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) {
+
+	const GDParser::FunctionNode* func=NULL;
+	for(int i=0;i<context._class->functions.size();i++) {
+		if (context._class->functions[i]->name==p_function) {
+			func=context._class->functions[i];
+			break;
+		}
+	}
+
+	if (!func)
+		return false;
+
+	for(int i=0;i<func->body->statements.size();i++) {
+
+
+
+		if (func->body->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
+			const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(func->body->statements[i]);
+			if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+
+				if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+					const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]);
+
+					if (id->name==p_identifier) {
+
+						return _guess_expression_type(context,op->arguments[1],func->body->statements[i]->line,r_type);
+					}
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
 static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
 static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
 
 
 	//go to block first
 	//go to block first
@@ -1089,8 +1127,22 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
 					r_type=_get_type_from_pinfo(context._class->variables[i]._export);
 					r_type=_get_type_from_pinfo(context._class->variables[i]._export);
 					return true;
 					return true;
 				} else if (context._class->variables[i].expression) {
 				} else if (context._class->variables[i].expression) {
-					return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
+
+					bool rtype = _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
+					if (rtype && r_type.type!=Variant::NIL)
+						return true;
+					//return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
 				}
 				}
+
+				//try to guess from assignment in construtor or _ready
+				if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_ready",r_type))
+					return true;
+				if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_enter_tree",r_type))
+					return true;
+				if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_init",r_type))
+					return true;
+
+				return false;
 			}
 			}
 		}
 		}
 	}
 	}

+ 72 - 10
modules/gdscript/gd_parser.cpp

@@ -170,6 +170,7 @@ void GDParser::_make_completable_call(int p_arg) {
 	completion_line=tokenizer->get_token_line();
 	completion_line=tokenizer->get_token_line();
 	completion_argument=p_arg;
 	completion_argument=p_arg;
 	completion_block=current_block;
 	completion_block=current_block;
+	completion_found=true;
 	tokenizer->advance();
 	tokenizer->advance();
 
 
 }
 }
@@ -190,6 +191,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide
 		completion_function=current_function;
 		completion_function=current_function;
 		completion_line=tokenizer->get_token_line();
 		completion_line=tokenizer->get_token_line();
 		completion_block=current_block;
 		completion_block=current_block;
+		completion_found=true;
 		tokenizer->advance();
 		tokenizer->advance();
 
 
 		if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
 		if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
@@ -1414,6 +1416,20 @@ GDParser::Node* GDParser::_parse_and_reduce_expression(Node *p_parent,bool p_sta
 	return expr;
 	return expr;
 }
 }
 
 
+bool GDParser::_recover_from_completion() {
+
+	if (!completion_found) {
+		return false; //can't recover if no completion
+	}
+	//skip stuff until newline
+	while(tokenizer->get_token()!=GDTokenizer::TK_NEWLINE && tokenizer->get_token()!=GDTokenizer::TK_EOF) {
+		tokenizer->advance();
+	}
+	completion_found=false;
+	error_set=false;
+	return true;
+}
+
 void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 
 	int indent_level = tab_level.back()->get();
 	int indent_level = tab_level.back()->get();
@@ -1511,8 +1527,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 					Node *subexpr=NULL;
 					Node *subexpr=NULL;
 
 
 					subexpr = _parse_and_reduce_expression(p_block,p_static);
 					subexpr = _parse_and_reduce_expression(p_block,p_static);
-					if (!subexpr)
+					if (!subexpr) {
+						if (_recover_from_completion()) {
+							break;
+						}
 						return;
 						return;
+					}
+
+
 
 
 					lv->assign=subexpr;
 					lv->assign=subexpr;
 					assigned=subexpr;
 					assigned=subexpr;
@@ -1543,8 +1565,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 
 				tokenizer->advance();
 				tokenizer->advance();
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
-				if (!condition)
+				if (!condition) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 
 
 				ControlFlowNode *cf_if = alloc_node<ControlFlowNode>();
 				ControlFlowNode *cf_if = alloc_node<ControlFlowNode>();
 
 
@@ -1598,8 +1624,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 
 						//condition
 						//condition
 						Node *condition = _parse_and_reduce_expression(p_block,p_static);
 						Node *condition = _parse_and_reduce_expression(p_block,p_static);
-						if (!condition)
+						if (!condition) {
+							if (_recover_from_completion()) {
+								break;
+							}
 							return;
 							return;
+						}
 						cf_else->arguments.push_back(condition);
 						cf_else->arguments.push_back(condition);
 						cf_else->cf_type=ControlFlowNode::CF_IF;
 						cf_else->cf_type=ControlFlowNode::CF_IF;
 
 
@@ -1660,8 +1690,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 
 				tokenizer->advance();
 				tokenizer->advance();
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
-				if (!condition)
+				if (!condition) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 
 
 				ControlFlowNode *cf_while = alloc_node<ControlFlowNode>();
 				ControlFlowNode *cf_while = alloc_node<ControlFlowNode>();
 
 
@@ -1706,8 +1740,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 				tokenizer->advance();
 				tokenizer->advance();
 
 
 				Node *container = _parse_and_reduce_expression(p_block,p_static);
 				Node *container = _parse_and_reduce_expression(p_block,p_static);
-				if (!container)
+				if (!container) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 
 
 				ControlFlowNode *cf_for = alloc_node<ControlFlowNode>();
 				ControlFlowNode *cf_for = alloc_node<ControlFlowNode>();
 
 
@@ -1771,8 +1809,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 				} else {
 				} else {
 					//expect expression
 					//expect expression
 					Node *retexpr = _parse_and_reduce_expression(p_block,p_static);
 					Node *retexpr = _parse_and_reduce_expression(p_block,p_static);
-					if (!retexpr)
+					if (!retexpr) {
+						if (_recover_from_completion()) {
+							break;
+						}
 						return;
 						return;
+					}
 					cf_return->arguments.push_back(retexpr);
 					cf_return->arguments.push_back(retexpr);
 					p_block->statements.push_back(cf_return);
 					p_block->statements.push_back(cf_return);
 					if (!_end_statement()) {
 					if (!_end_statement()) {
@@ -1787,8 +1829,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 
 				tokenizer->advance();
 				tokenizer->advance();
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
 				Node *condition = _parse_and_reduce_expression(p_block,p_static);
-				if (!condition)
+				if (!condition) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 				AssertNode *an = alloc_node<AssertNode>();
 				AssertNode *an = alloc_node<AssertNode>();
 				an->condition=condition;
 				an->condition=condition;
 				p_block->statements.push_back(an);
 				p_block->statements.push_back(an);
@@ -1801,8 +1847,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 			default: {
 			default: {
 
 
 				Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true);
 				Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true);
-				if (!expression)
+				if (!expression) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 				p_block->statements.push_back(expression);
 				p_block->statements.push_back(expression);
 				if (!_end_statement()) {
 				if (!_end_statement()) {
 					_set_error("Expected end of statement after expression.");
 					_set_error("Expected end of statement after expression.");
@@ -2626,8 +2676,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
 					Node *subexpr=NULL;
 					Node *subexpr=NULL;
 
 
 					subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
 					subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
-					if (!subexpr)
+					if (!subexpr) {
+						if (_recover_from_completion()) {
+							break;
+						}
 						return;
 						return;
+					}
 
 
 					member.expression=subexpr;
 					member.expression=subexpr;
 
 
@@ -2756,8 +2810,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
 				Node *subexpr=NULL;
 				Node *subexpr=NULL;
 
 
 				subexpr = _parse_and_reduce_expression(p_class,true,true);
 				subexpr = _parse_and_reduce_expression(p_class,true,true);
-				if (!subexpr)
+				if (!subexpr) {
+					if (_recover_from_completion()) {
+						break;
+					}
 					return;
 					return;
+				}
 
 
 				if (subexpr->type!=Node::TYPE_CONSTANT) {
 				if (subexpr->type!=Node::TYPE_CONSTANT) {
 					_set_error("Expected constant expression");
 					_set_error("Expected constant expression");
@@ -2852,6 +2910,7 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
 	completion_class=NULL;
 	completion_class=NULL;
 	completion_function=NULL;
 	completion_function=NULL;
 	completion_block=NULL;
 	completion_block=NULL;
+	completion_found=false;
 	current_block=NULL;
 	current_block=NULL;
 	current_class=NULL;
 	current_class=NULL;
 	current_function=NULL;
 	current_function=NULL;
@@ -2874,6 +2933,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju
 	completion_class=NULL;
 	completion_class=NULL;
 	completion_function=NULL;
 	completion_function=NULL;
 	completion_block=NULL;
 	completion_block=NULL;
+	completion_found=false;
 	current_block=NULL;
 	current_block=NULL;
 	current_class=NULL;
 	current_class=NULL;
 
 
@@ -2917,6 +2977,8 @@ void GDParser::clear() {
 	current_block=NULL;
 	current_block=NULL;
 	current_class=NULL;
 	current_class=NULL;
 
 
+	completion_found=false;
+
 	current_function=NULL;
 	current_function=NULL;
 
 
 	validating=false;
 	validating=false;

+ 2 - 0
modules/gdscript/gd_parser.h

@@ -419,10 +419,12 @@ private:
 	BlockNode *completion_block;
 	BlockNode *completion_block;
 	int completion_line;
 	int completion_line;
 	int completion_argument;
 	int completion_argument;
+	bool completion_found;
 
 
 	PropertyInfo current_export;
 	PropertyInfo current_export;
 
 
 	void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
 	void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
+	bool _recover_from_completion();
 
 
 
 
 	bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);
 	bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);