detect node and variable assignments in _ready, _init, etc for further code completion
This commit is contained in:
parent
947b283248
commit
319cc7e3ae
3 changed files with 127 additions and 11 deletions
|
@ -998,6 +998,44 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l
|
|||
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) {
|
||||
|
||||
//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);
|
||||
return true;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,7 @@ void GDParser::_make_completable_call(int p_arg) {
|
|||
completion_line=tokenizer->get_token_line();
|
||||
completion_argument=p_arg;
|
||||
completion_block=current_block;
|
||||
completion_found=true;
|
||||
tokenizer->advance();
|
||||
|
||||
}
|
||||
|
@ -190,6 +191,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide
|
|||
completion_function=current_function;
|
||||
completion_line=tokenizer->get_token_line();
|
||||
completion_block=current_block;
|
||||
completion_found=true;
|
||||
tokenizer->advance();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
int indent_level = tab_level.back()->get();
|
||||
|
@ -1511,8 +1527,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
Node *subexpr=NULL;
|
||||
|
||||
subexpr = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!subexpr)
|
||||
if (!subexpr) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
lv->assign=subexpr;
|
||||
assigned=subexpr;
|
||||
|
@ -1543,8 +1565,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
|
||||
tokenizer->advance();
|
||||
Node *condition = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!condition)
|
||||
if (!condition) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ControlFlowNode *cf_if = alloc_node<ControlFlowNode>();
|
||||
|
||||
|
@ -1598,8 +1624,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
|
||||
//condition
|
||||
Node *condition = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!condition)
|
||||
if (!condition) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
cf_else->arguments.push_back(condition);
|
||||
cf_else->cf_type=ControlFlowNode::CF_IF;
|
||||
|
||||
|
@ -1660,8 +1690,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
|
||||
tokenizer->advance();
|
||||
Node *condition = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!condition)
|
||||
if (!condition) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ControlFlowNode *cf_while = alloc_node<ControlFlowNode>();
|
||||
|
||||
|
@ -1706,8 +1740,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
tokenizer->advance();
|
||||
|
||||
Node *container = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!container)
|
||||
if (!container) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ControlFlowNode *cf_for = alloc_node<ControlFlowNode>();
|
||||
|
||||
|
@ -1771,8 +1809,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
} else {
|
||||
//expect expression
|
||||
Node *retexpr = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!retexpr)
|
||||
if (!retexpr) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
cf_return->arguments.push_back(retexpr);
|
||||
p_block->statements.push_back(cf_return);
|
||||
if (!_end_statement()) {
|
||||
|
@ -1787,8 +1829,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
|
||||
tokenizer->advance();
|
||||
Node *condition = _parse_and_reduce_expression(p_block,p_static);
|
||||
if (!condition)
|
||||
if (!condition) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
AssertNode *an = alloc_node<AssertNode>();
|
||||
an->condition=condition;
|
||||
p_block->statements.push_back(an);
|
||||
|
@ -1801,8 +1847,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
default: {
|
||||
|
||||
Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true);
|
||||
if (!expression)
|
||||
if (!expression) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
p_block->statements.push_back(expression);
|
||||
if (!_end_statement()) {
|
||||
_set_error("Expected end of statement after expression.");
|
||||
|
@ -2626,8 +2676,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
Node *subexpr=NULL;
|
||||
|
||||
subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
|
||||
if (!subexpr)
|
||||
if (!subexpr) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
member.expression=subexpr;
|
||||
|
||||
|
@ -2756,8 +2810,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
Node *subexpr=NULL;
|
||||
|
||||
subexpr = _parse_and_reduce_expression(p_class,true,true);
|
||||
if (!subexpr)
|
||||
if (!subexpr) {
|
||||
if (_recover_from_completion()) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (subexpr->type!=Node::TYPE_CONSTANT) {
|
||||
_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_function=NULL;
|
||||
completion_block=NULL;
|
||||
completion_found=false;
|
||||
current_block=NULL;
|
||||
current_class=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_function=NULL;
|
||||
completion_block=NULL;
|
||||
completion_found=false;
|
||||
current_block=NULL;
|
||||
current_class=NULL;
|
||||
|
||||
|
@ -2917,6 +2977,8 @@ void GDParser::clear() {
|
|||
current_block=NULL;
|
||||
current_class=NULL;
|
||||
|
||||
completion_found=false;
|
||||
|
||||
current_function=NULL;
|
||||
|
||||
validating=false;
|
||||
|
|
|
@ -419,10 +419,12 @@ private:
|
|||
BlockNode *completion_block;
|
||||
int completion_line;
|
||||
int completion_argument;
|
||||
bool completion_found;
|
||||
|
||||
PropertyInfo current_export;
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue