summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/SCsub2
-rw-r--r--modules/gdscript/gd_editor.cpp54
-rw-r--r--modules/gdscript/gd_functions.cpp9
-rw-r--r--modules/gdscript/gd_parser.cpp146
-rw-r--r--modules/gdscript/gd_parser.h3
-rw-r--r--modules/gdscript/gd_script.cpp7
-rw-r--r--modules/gdscript/gd_script.h2
7 files changed, 187 insertions, 36 deletions
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index d20da72b72..403fe68f66 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.modules_sources,"*.cpp")
Export('env')
-
-
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index 7cb9882f3a..0d986e92a2 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -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;
}
}
}
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 37ddb2bc41..6f51ac5312 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -904,6 +904,15 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret = gdscr->_new(NULL,0,r_error);
+ GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance());
+ Ref<GDScript> gd_ref = ins->get_script();
+
+ for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
+ if(d.has(E->key())) {
+ ins->members[E->get().index] = d[E->key()];
+ }
+ }
+
} break;
case HASH: {
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index f7aaaf7ee5..202ab76da0 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -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,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();
@@ -1511,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;
@@ -1543,8 +1569,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 +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;
@@ -1660,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>();
@@ -1706,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>();
@@ -1771,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()) {
@@ -1787,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);
@@ -1801,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.");
@@ -1886,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();
@@ -2367,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) {
@@ -2517,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: {
@@ -2553,23 +2634,16 @@ void GDParser::_parse_class(ClassNode *p_class) {
} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
String identifier = tokenizer->get_token_identifier();
- if (identifier == "flag") {
- current_export.type=Variant::INT;
- current_export.hint=PROPERTY_HINT_ALL_FLAGS;
- }else if (identifier == "multiline"){
- current_export.type=Variant::STRING;
- current_export.hint=PROPERTY_HINT_MULTILINE_TEXT;
- } else {
- if (!ObjectTypeDB::is_type(identifier,"Resource")) {
-
- current_export=PropertyInfo();
- _set_error("Export hint not a type or resource.");
- }
-
- current_export.type=Variant::OBJECT;
- current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
- current_export.hint_string=identifier;
+ if (!ObjectTypeDB::is_type(identifier,"Resource")) {
+
+ current_export=PropertyInfo();
+ _set_error("Export hint not a type or resource.");
}
+
+ current_export.type=Variant::OBJECT;
+ current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
+ current_export.hint_string=identifier;
+
tokenizer->advance();
}
@@ -2625,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;
@@ -2640,7 +2718,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
member._export.type=Variant::DICTIONARY;
- } else {
+ } else*/ {
if (subexpr->type!=Node::TYPE_CONSTANT) {
@@ -2756,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");
@@ -2852,6 +2934,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 +2957,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 +3001,8 @@ void GDParser::clear() {
current_block=NULL;
current_class=NULL;
+ completion_found=false;
+
current_function=NULL;
validating=false;
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index fd8a2576fa..04f3dff3de 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -276,7 +276,6 @@ public:
};
struct NewLineNode : public Node {
- int line;
NewLineNode() { type=TYPE_NEWLINE; }
};
@@ -419,10 +418,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);
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 53ae0c8702..99ddc74bb4 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -2710,7 +2710,10 @@ GDScriptLanguage::~GDScriptLanguage() {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderGDScript::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
GDScript *script = memnew( GDScript );
@@ -2742,6 +2745,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
script->reload();
}
+ if (r_error)
+ *r_error=OK;
return scriptres;
}
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index fe325ff71e..37ef47af6c 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -557,7 +557,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;