summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gd_script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gd_script.cpp')
-rw-r--r--modules/gdscript/gd_script.cpp347
1 files changed, 291 insertions, 56 deletions
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 75bb47ceab..92962fa3f7 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -31,6 +31,7 @@
#include "global_constants.h"
#include "gd_compiler.h"
#include "os/file_access.h"
+#include "io/file_access_encrypted.h"
/* TODO:
@@ -61,6 +62,10 @@ Variant *GDFunction::_get_variant(int p_address,GDInstance *p_instance,GDScript
}
return &self;
} break;
+ case ADDR_TYPE_CLASS: {
+
+ return &p_script->_static_ref;
+ } break;
case ADDR_TYPE_MEMBER: {
//member indexing is O(1)
if (!p_instance) {
@@ -72,16 +77,21 @@ Variant *GDFunction::_get_variant(int p_address,GDInstance *p_instance,GDScript
case ADDR_TYPE_CLASS_CONSTANT: {
//todo change to index!
- GDScript *s=p_script;
+ GDScript *o=p_script;
ERR_FAIL_INDEX_V(address,_global_names_count,NULL);
const StringName *sn = &_global_names_ptr[address];
- while(s) {
- Map<StringName,Variant>::Element *E=s->constants.find(*sn);
- if (E) {
- return &E->get();
+ while(o) {
+ GDScript *s=o;
+ while(s) {
+
+ Map<StringName,Variant>::Element *E=s->constants.find(*sn);
+ if (E) {
+ return &E->get();
+ }
+ s=s->_base;
}
- s=s->_base;
+ o=o->_owner;
}
@@ -173,7 +183,7 @@ static String _get_var_type(const Variant* p_type) {
}
-Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err) {
+Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError& r_err, CallState *p_state) {
if (!_code_ptr) {
@@ -195,77 +205,91 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
#endif
- if (p_argcount!=_argument_count) {
+ uint32_t alloca_size=0;
+ GDScript *_class;
+ int ip=0;
+ int line=_initial_line;
- if (p_argcount>_argument_count) {
+ if (p_state) {
+ //use existing (supplied) state (yielded)
+ stack=(Variant*)p_state->stack.ptr();
+ call_args=(Variant**)&p_state->stack[sizeof(Variant)*p_state->stack_size];
+ line=p_state->line;
+ ip=p_state->ip;
+ alloca_size=p_state->stack.size();
+ _class=p_state->_class;
+ p_instance=p_state->instance;
+ defarg=p_state->defarg;
+ self=p_state->self;
+ //stack[p_state->result_pos]=p_state->result; //assign stack with result
- r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_err.argument=_argument_count;
+ } else {
- return Variant();
- } else if (p_argcount < _argument_count - _default_arg_count) {
+ if (p_argcount!=_argument_count) {
- r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_err.argument=_argument_count - _default_arg_count;
- return Variant();
- } else {
+ if (p_argcount>_argument_count) {
- defarg=_argument_count-p_argcount;
- }
- }
+ r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_err.argument=_argument_count;
- uint32_t alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size;
+ return Variant();
+ } else if (p_argcount < _argument_count - _default_arg_count) {
- if (alloca_size) {
+ r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_err.argument=_argument_count - _default_arg_count;
+ return Variant();
+ } else {
- uint8_t *aptr = (uint8_t*)alloca(alloca_size);
+ defarg=_argument_count-p_argcount;
+ }
+ }
- if (_stack_size) {
+ alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size;
- stack=(Variant*)aptr;
- for(int i=0;i<p_argcount;i++)
- memnew_placement(&stack[i],Variant(*p_args[i]));
- for(int i=p_argcount;i<_stack_size;i++)
- memnew_placement(&stack[i],Variant);
- } else {
- stack=NULL;
- }
+ if (alloca_size) {
- if (_call_size) {
+ uint8_t *aptr = (uint8_t*)alloca(alloca_size);
- call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size];
- } else {
+ if (_stack_size) {
- call_args=NULL;
- }
+ stack=(Variant*)aptr;
+ for(int i=0;i<p_argcount;i++)
+ memnew_placement(&stack[i],Variant(*p_args[i]));
+ for(int i=p_argcount;i<_stack_size;i++)
+ memnew_placement(&stack[i],Variant);
+ } else {
+ stack=NULL;
+ }
+ if (_call_size) {
- } else {
- stack=NULL;
- call_args=NULL;
- }
+ call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size];
+ } else {
+
+ call_args=NULL;
+ }
- GDScript *_class;
+ } else {
+ stack=NULL;
+ call_args=NULL;
+ }
- if (p_instance) {
- if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) {
+ if (p_instance) {
+ if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) {
- self=REF(static_cast<Reference*>(p_instance->owner));
+ self=REF(static_cast<Reference*>(p_instance->owner));
+ } else {
+ self=p_instance->owner;
+ }
+ _class=p_instance->script.ptr();
} else {
- self=p_instance->owner;
+ _class=_script;
}
- _class=p_instance->script.ptr();
- } else {
- _class=_script;
}
- int ip=0;
- int line=_initial_line;
String err_text;
-
-
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton())
@@ -380,6 +404,8 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
}
}
+
+
} else {
GDNativeClass *nc= obj_B->cast_to<GDNativeClass>();
@@ -772,6 +798,97 @@ Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_ar
ip+=4+argc;
} continue;
+ case OPCODE_YIELD:
+ case OPCODE_YIELD_SIGNAL: {
+
+ int ipofs=1;
+ if (_code_ptr[ip]==OPCODE_YIELD_SIGNAL) {
+ CHECK_SPACE(4);
+ ipofs+=2;
+ } else {
+ CHECK_SPACE(2);
+
+ }
+
+ Ref<GDFunctionState> gdfs = memnew( GDFunctionState );
+ gdfs->function=this;
+
+ gdfs->state.stack.resize(alloca_size);
+ //copy variant stack
+ for(int i=0;i<_stack_size;i++) {
+ memnew_placement(&stack[sizeof(Variant)*i],Variant(stack[i]));
+ }
+ gdfs->state.stack_size=_stack_size;
+ gdfs->state.self=self;
+ gdfs->state.alloca_size=alloca_size;
+ gdfs->state._class=_class;
+ gdfs->state.ip=ip+ipofs;
+ gdfs->state.line=line;
+ //gdfs->state.result_pos=ip+ipofs-1;
+ gdfs->state.defarg=defarg;
+ gdfs->state.instance=p_instance;
+ gdfs->function=this;
+
+ retvalue=gdfs;
+
+ if (_code_ptr[ip]==OPCODE_YIELD_SIGNAL) {
+ GET_VARIANT_PTR(argobj,1);
+ GET_VARIANT_PTR(argname,2);
+ //do the oneshot connect
+
+ if (argobj->get_type()!=Variant::OBJECT) {
+ err_text="First argument of yield() not of type object.";
+ break;
+ }
+ if (argname->get_type()!=Variant::STRING) {
+ err_text="Second argument of yield() not a string (for signal name).";
+ break;
+ }
+ Object *obj=argobj->operator Object *();
+ String signal = argname->operator String();
+#ifdef DEBUG_ENABLED
+
+ if (!obj) {
+ err_text="First argument of yield() is null.";
+ break;
+ }
+ if (ScriptDebugger::get_singleton()) {
+ if (!ObjectDB::instance_validate(obj)) {
+ err_text="First argument of yield() is a previously freed instance.";
+ break;
+ }
+ }
+ if (signal.length()==0) {
+
+ err_text="Second argument of yield() is an empty string (for signal name).";
+ break;
+ }
+
+#endif
+ Error err = obj->connect(signal,gdfs.ptr(),"_signal_callback",varray(gdfs),Object::CONNECT_ONESHOT);
+ if (err!=OK) {
+ err_text="Error connecting to signal: "+signal+" during yield().";
+ break;
+ }
+
+
+ }
+
+ exit_ok=true;
+
+ } break;
+ case OPCODE_YIELD_RESUME: {
+
+ CHECK_SPACE(2);
+ if (!p_state) {
+ err_text=("Invalid Resume (bug?)");
+ break;
+ }
+ GET_VARIANT_PTR(result,1);
+ *result=p_state->result;
+ ip+=2;
+
+ } continue;
case OPCODE_JUMP: {
CHECK_SPACE(2);
@@ -1150,9 +1267,99 @@ GDFunction::GDFunction() {
_stack_size=0;
_call_size=0;
name="<anonymous>";
+#ifdef DEBUG_ENABLED
+ _func_cname=NULL;
+#endif
+
+}
+
+/////////////////////
+
+
+Variant GDFunctionState::_signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ Variant arg;
+ r_error.error=Variant::CallError::CALL_OK;
+
+ ERR_FAIL_COND_V(!function,Variant());
+
+ if (p_argcount==0) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=1;
+ return Variant();
+ } else if (p_argcount==1) {
+ //noooneee
+ } else if (p_argcount==2) {
+ arg=*p_args[0];
+ } else {
+ Array extra_args;
+ for(int i=0;i<p_argcount-1;i++) {
+ extra_args.push_back(*p_args[i]);
+ }
+ arg=extra_args;
+ }
+
+ Ref<GDFunctionState> self = *p_args[p_argcount-1];
+
+ if (self.is_null()) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=p_argcount-1;
+ r_error.expected=Variant::OBJECT;
+ return Variant();
+ }
+ state.result=arg;
+ Variant ret = function->call(NULL,NULL,0,r_error,&state);
+ function=NULL; //cleaned up;
+ state.result=Variant();
+ return ret;
}
+
+bool GDFunctionState::is_valid() const {
+
+ return function!=NULL;
+}
+
+Variant GDFunctionState::resume(const Variant& p_arg) {
+
+ ERR_FAIL_COND_V(!function,Variant());
+
+ state.result=p_arg;
+ Variant::CallError err;
+ Variant ret = function->call(NULL,NULL,0,err,&state);
+ function=NULL; //cleaned up;
+ state.result=Variant();
+ return ret;
+}
+
+
+void GDFunctionState::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("resume:var","arg"),&GDFunctionState::resume,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid);
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback"));
+
+}
+
+GDFunctionState::GDFunctionState() {
+
+ function=NULL;
+}
+
+GDFunctionState::~GDFunctionState() {
+
+ if (function!=NULL) {
+ //never called, deinitialize stack
+ for(int i=0;i<state.stack_size;i++) {
+ Variant *v=(Variant*)&state.stack[sizeof(Variant)*i];
+ v->~Variant();
+ }
+ }
+}
+
+///////////////////////////
+
GDNativeClass::GDNativeClass(const StringName& p_name) {
name=p_name;
@@ -1436,6 +1643,7 @@ Error GDScript::reload() {
+
valid=false;
GDParser parser;
Error err = parser.parse(source,basedir);
@@ -1577,7 +1785,28 @@ void GDScript::_bind_methods() {
Error GDScript::load_byte_code(const String& p_path) {
- Vector<uint8_t> bytecode = FileAccess::get_file_as_array(p_path);
+ Vector<uint8_t> bytecode;
+
+ if (p_path.ends_with("gde")) {
+
+ FileAccess *fa = FileAccess::open(p_path,FileAccess::READ);
+ ERR_FAIL_COND_V(!fa,ERR_CANT_OPEN);
+ FileAccessEncrypted *fae = memnew( FileAccessEncrypted );
+ ERR_FAIL_COND_V(!fae,ERR_CANT_OPEN);
+ Vector<uint8_t> key;
+ key.resize(32);
+ for(int i=0;i<key.size();i++) {
+ key[i]=script_encryption_key[i];
+ }
+ Error err = fae->open_and_parse(fa,key,FileAccessEncrypted::MODE_READ);
+ ERR_FAIL_COND_V(err,err);
+ bytecode.resize(fae->get_len());
+ fae->get_buffer(bytecode.ptr(),bytecode.size());
+ memdelete(fae);
+ } else {
+
+ bytecode = FileAccess::get_file_as_array(p_path);
+ }
ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR);
path=p_path;
@@ -1678,12 +1907,14 @@ Ref<GDScript> GDScript::get_base() const {
GDScript::GDScript() {
+ _static_ref=this;
valid=false;
subclass_count=0;
initializer=NULL;
_base=NULL;
_owner=NULL;
tool=false;
+
}
@@ -2143,6 +2374,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"and",
"or",
"export",
+ "assert",
+ "yield",
+ "static",
0};
@@ -2209,7 +2443,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
Ref<GDScript> scriptres(script);
- if (p_path.ends_with(".gdc")) {
+ if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) {
script->set_script_path(p_original_path); // script needs this.
script->set_path(p_original_path);
@@ -2242,6 +2476,7 @@ void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_ext
p_extensions->push_back("gd");
p_extensions->push_back("gdc");
+ p_extensions->push_back("gde");
}
bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
@@ -2252,7 +2487,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
String el = p_path.extension().to_lower();
- if (el=="gd" || el=="gdc")
+ if (el=="gd" || el=="gdc" || el=="gde")
return "GDScript";
return "";
}