diff options
Diffstat (limited to 'modules/gdscript/gd_parser.cpp')
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 224 |
1 files changed, 200 insertions, 24 deletions
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 6242400663..202ab76da0 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -30,6 +30,7 @@ #include "print_string.h" #include "io/resource_loader.h" #include "os/file_access.h" +#include "script_language.h" template<class T> T* GDParser::alloc_node() { @@ -116,6 +117,14 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) { _make_completable_call(argidx); completion_node=p_parent; + } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING && tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) { + //completing a string argument.. + completion_cursor=tokenizer->get_token_constant(); + + _make_completable_call(argidx); + completion_node=p_parent; + tokenizer->advance(1); + return false; } Node*arg = _parse_expression(p_parent,p_static); @@ -161,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(); } @@ -181,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) { @@ -277,7 +288,11 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ if (!validating) { //this can be too slow for just validating code - res = ResourceLoader::load(path); + if (for_completion && ScriptCodeCompletionCache::get_sigleton()) { + res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path); + } else { + res = ResourceLoader::load(path); + } if (!res.is_valid()) { _set_error("Can't preload resource at path: "+path); return NULL; @@ -1401,6 +1416,24 @@ 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->get_token()!=GDTokenizer::TK_ERROR) { + tokenizer->advance(); + } + completion_found=false; + error_set=false; + if(tokenizer->get_token() == GDTokenizer::TK_ERROR){ + error_set = true; + } + + return true; +} + void GDParser::_parse_block(BlockNode *p_block,bool p_static) { int indent_level = tab_level.back()->get(); @@ -1498,8 +1531,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; @@ -1520,16 +1559,22 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { op->arguments.push_back(assigned); p_block->statements.push_back(op); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (var)"); + return; + } } break; case GDTokenizer::TK_CF_IF: { 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>(); @@ -1583,8 +1628,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; @@ -1645,8 +1694,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>(); @@ -1691,8 +1744,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>(); @@ -1756,8 +1813,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()) { @@ -1772,8 +1833,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); @@ -1786,8 +1851,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."); @@ -1871,9 +1940,15 @@ void GDParser::_parse_extends(ClassNode *p_class) { p_class->extends_used=true; - //see if inheritance happens from a file tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer->get_token_type()==Variant::OBJECT) { + p_class->extends_class.push_back(Variant::get_type_name(Variant::OBJECT)); + tokenizer->advance(); + return; + } + + // see if inheritance happens from a file if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) { Variant constant = tokenizer->get_token_constant(); @@ -1946,8 +2021,10 @@ void GDParser::_parse_class(ClassNode *p_class) { _parse_extends(p_class); if (error_set) return; - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement after extends"); + return; + } } break; case GDTokenizer::TK_PR_TOOL: { @@ -2227,6 +2304,53 @@ void GDParser::_parse_class(ClassNode *p_class) { //arguments } break; + case GDTokenizer::TK_PR_SIGNAL: { + tokenizer->advance(); + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier after 'signal'."); + return; + } + + ClassNode::Signal sig; + sig.name = tokenizer->get_token_identifier(); + tokenizer->advance(); + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + tokenizer->advance(); + while(true) { + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier in signal argument."); + return; + } + + sig.arguments.push_back(tokenizer->get_token_identifier()); + tokenizer->advance(); + + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ',' or ')' after signal parameter identifier."); + return; + } + } + } + + p_class->_signals.push_back(sig); + + if (!_end_statement()) { + _set_error("Expected end of statement (signal)"); + return; + } + } break; case GDTokenizer::TK_PR_EXPORT: { tokenizer->advance(); @@ -2251,6 +2375,17 @@ void GDParser::_parse_class(ClassNode *p_class) { case Variant::INT: { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") { + + current_export.hint=PROPERTY_HINT_ALL_FLAGS; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } + if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) { //enumeration current_export.hint=PROPERTY_HINT_ENUM; @@ -2292,6 +2427,16 @@ void GDParser::_parse_class(ClassNode *p_class) { }; //fallthrough to use the same case Variant::REAL: { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="EASE") { + current_export.hint=PROPERTY_HINT_EXP_EASING; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } + float sign=1.0; if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) { @@ -2442,6 +2587,17 @@ void GDParser::_parse_class(ClassNode *p_class) { } break; } + + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="MULTILINE") { + + current_export.hint=PROPERTY_HINT_MULTILINE_TEXT; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } } break; case Variant::COLOR: { @@ -2543,14 +2699,18 @@ void GDParser::_parse_class(ClassNode *p_class) { Node *subexpr=NULL; - subexpr = _parse_and_reduce_expression(p_class,false); - if (!subexpr) + subexpr = _parse_and_reduce_expression(p_class,false,autoexport); + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } member.expression=subexpr; if (autoexport) { - if (subexpr->type==Node::TYPE_ARRAY) { + if (1)/*(subexpr->type==Node::TYPE_ARRAY) { member._export.type=Variant::ARRAY; @@ -2558,7 +2718,7 @@ void GDParser::_parse_class(ClassNode *p_class) { member._export.type=Variant::DICTIONARY; - } else { + } else*/ { if (subexpr->type!=Node::TYPE_CONSTANT) { @@ -2644,8 +2804,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (continue)"); + return; + } } break; case GDTokenizer::TK_PR_CONST: { //variale declaration and (eventual) initialization @@ -2672,8 +2834,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"); @@ -2682,8 +2848,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.push_back(constant); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (constant)"); + return; + } } break; @@ -2759,11 +2927,14 @@ Error GDParser::_parse(const String& p_base_path) { Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) { + for_completion=false; + validating=false; completion_type=COMPLETION_NONE; completion_node=NULL; completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; current_function=NULL; @@ -2779,13 +2950,14 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p } -Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) { +Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path,bool p_for_completion) { completion_type=COMPLETION_NONE; completion_node=NULL; completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; @@ -2796,6 +2968,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju tt->set_code(p_code); validating=p_just_validate; + for_completion=p_for_completion; tokenizer=tt; Error ret = _parse(p_base_path); memdelete(tt); @@ -2828,9 +3001,12 @@ void GDParser::clear() { current_block=NULL; current_class=NULL; + completion_found=false; + current_function=NULL; validating=false; + for_completion=false; error_set=false; tab_level.clear(); tab_level.push_back(0); |