| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281 | /*************************************************************************//*  gd_script.cpp                                                        *//*************************************************************************//*                       This file is part of:                           *//*                           GODOT ENGINE                                *//*                    http://www.godotengine.org                         *//*************************************************************************//* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 *//*                                                                       *//* Permission is hereby granted, free of charge, to any person obtaining *//* a copy of this software and associated documentation files (the       *//* "Software"), to deal in the Software without restriction, including   *//* without limitation the rights to use, copy, modify, merge, publish,   *//* distribute, sublicense, and/or sell copies of the Software, and to    *//* permit persons to whom the Software is furnished to do so, subject to *//* the following conditions:                                             *//*                                                                       *//* The above copyright notice and this permission notice shall be        *//* included in all copies or substantial portions of the Software.       *//*                                                                       *//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  *//* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  *//* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     *//* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *//*************************************************************************/#include "gd_script.h"#include "globals.h"#include "global_constants.h"#include "gd_compiler.h"#include "os/file_access.h"/* TODO:   *populate globals   *do checks as close to debugger as possible (but don't do debugger)   *const check plz   *check arguments and default arguments in GDFunction   -get property list in instance?   *missing opcodes   -const checks   -make thread safe */Variant *GDFunction::_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self, Variant *p_stack,String& r_error) const{	int address = p_address&ADDR_MASK;	//sequential table (jump table generated by compiler)	switch((p_address&ADDR_TYPE_MASK)>>ADDR_BITS) {		case ADDR_TYPE_SELF: {			if (!p_instance) {				r_error="Cannot access self without instance.";				return NULL;			}			return &self;		} break;		case ADDR_TYPE_MEMBER: {			//member indexing is O(1)			if (!p_instance) {				r_error="Cannot access member without instance.";				return NULL;			}			return &p_instance->members[address];		} break;		case ADDR_TYPE_CLASS_CONSTANT: {			//todo change to index!			GDScript *s=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();				}				s=s->_base;			}			ERR_EXPLAIN("GDCompiler bug..");			ERR_FAIL_V(NULL);		} break;		case ADDR_TYPE_LOCAL_CONSTANT: {			ERR_FAIL_INDEX_V(address,_constant_count,NULL);			return &_constants_ptr[address];		} break;		case ADDR_TYPE_STACK:		case ADDR_TYPE_STACK_VARIABLE: {			ERR_FAIL_INDEX_V(address,_stack_size,NULL);			return &p_stack[address];		} break;		case ADDR_TYPE_GLOBAL: {			ERR_FAIL_INDEX_V(address,GDScriptLanguage::get_singleton()->get_global_array_size(),NULL);			return &GDScriptLanguage::get_singleton()->get_global_array()[address];		} break;		case ADDR_TYPE_NIL: {			return &nil;		} break;	}	ERR_EXPLAIN("Bad Code! (Addressing Mode)");	ERR_FAIL_V(NULL);	return NULL;}String GDFunction::_get_call_error(const Variant::CallError& p_err, const String& p_where,const Variant**argptrs) const {	String err_text;	if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {		int errorarg=p_err.argument;		err_text="Invalid type in "+p_where+". Cannot convert argument "+itos(errorarg+1)+" from "+Variant::get_type_name(argptrs[errorarg]->get_type())+" to "+Variant::get_type_name(p_err.expected)+".";	} else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {		err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments.";	} else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {		err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments.";	} else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {		err_text="Invalid call. Unexisting "+p_where+".";	} else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {		err_text="Attempt to call "+p_where+" on a null instance.";	} else {		err_text="Bug, call error: #"+itos(p_err.error);	}	return err_text;}static String _get_var_type(const Variant* p_type) {	String basestr;	if (p_type->get_type()==Variant::OBJECT) {		Object *bobj = *p_type;		if (!bobj) {			basestr = "null instance";		} else {#ifdef DEBUG_ENABLED			if (ObjectDB::instance_validate(bobj)) {				if (bobj->get_script_instance())					basestr= bobj->get_type()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")";				else					basestr = bobj->get_type();			} else {				basestr="previously freed instance";			}#else			basestr="Object";#endif		}	} else {		basestr = Variant::get_type_name(p_type->get_type());	}	return basestr;}Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err) {	if (!_code_ptr) {		return Variant();	}	r_err.error=Variant::CallError::CALL_OK;	Variant self;	Variant retvalue;	Variant *stack = NULL;	Variant **call_args;	int defarg=0;#ifdef DEBUG_ENABLED	//GDScriptLanguage::get_singleton()->calls++;#endif	if (p_argcount!=_argument_count) {		if (p_argcount>_argument_count) {			r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;			r_err.argument=_argument_count;			return Variant();		} else if (p_argcount < _argument_count - _default_arg_count) {			r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;			r_err.argument=_argument_count - _default_arg_count;			return Variant();		} else {			defarg=_argument_count-p_argcount;		}	}	uint32_t alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size;	if (alloca_size) {		uint8_t *aptr = (uint8_t*)alloca(alloca_size);		if (_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 (_call_size) {			call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size];		} else {			call_args=NULL;		}	} else {		stack=NULL;		call_args=NULL;	}	GDScript *_class;	if (p_instance) {		if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) {			self=REF(static_cast<Reference*>(p_instance->owner));		} else {			self=p_instance->owner;		}		_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())        GDScriptLanguage::get_singleton()->enter_function(p_instance,this,stack,&ip,&line);#define CHECK_SPACE(m_space)\	ERR_BREAK((ip+m_space)>_code_size)#define GET_VARIANT_PTR(m_v,m_code_ofs) \	Variant *m_v; \	m_v = _get_variant(_code_ptr[ip+m_code_ofs],p_instance,_class,self,stack,err_text);\	if (!m_v)\		break;#else#define CHECK_SPACE(m_space)#define GET_VARIANT_PTR(m_v,m_code_ofs) \	Variant *m_v; \	m_v = _get_variant(_code_ptr[ip+m_code_ofs],p_instance,_class,self,stack,err_text);#endif	bool exit_ok=false;	while(ip<_code_size) {		int last_opcode=_code_ptr[ip];		switch(_code_ptr[ip]) {			case OPCODE_OPERATOR: {				CHECK_SPACE(5);				bool valid;				Variant::Operator op = (Variant::Operator)_code_ptr[ip+1];				ERR_BREAK(op>=Variant::OP_MAX);				GET_VARIANT_PTR(a,2);				GET_VARIANT_PTR(b,3);				GET_VARIANT_PTR(dst,4);				Variant::evaluate(op,*a,*b,*dst,valid);				if (!valid) {					if (false && dst->get_type()==Variant::STRING) {						//return a string when invalid with the error						err_text=*dst;					} else {						err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'.";					}					break;				}				ip+=5;			} continue;			case OPCODE_EXTENDS_TEST: {				CHECK_SPACE(4);				GET_VARIANT_PTR(a,1);				GET_VARIANT_PTR(b,2);				GET_VARIANT_PTR(dst,3);#ifdef DEBUG_ENABLED				if (a->get_type()!=Variant::OBJECT || a->operator Object*()==NULL) {					err_text="Left operand of 'extends' is not an instance of anything.";					break;				}				if (b->get_type()!=Variant::OBJECT || b->operator Object*()==NULL) {					err_text="Right operand of 'extends' is not a class.";					break;				}#endif				Object *obj_A = *a;				Object *obj_B = *b;				GDScript *scr_B = obj_B->cast_to<GDScript>();				bool extends_ok=false;				if (scr_B) {					//if B is a script, the only valid condition is that A has an instance which inherits from the script					//in other situation, this shoul return false.					if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language()==GDScriptLanguage::get_singleton()) {						GDInstance *ins = static_cast<GDInstance*>(obj_A->get_script_instance());						GDScript *cmp = ins->script.ptr();						//bool found=false;						while(cmp) {							if (cmp==scr_B) {								//inherits from script, all ok								extends_ok=true;								break;							}							cmp=cmp->_base;						}					}				} else {					GDNativeClass *nc= obj_B->cast_to<GDNativeClass>();					if (!nc) {						err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_type()+"').";						break;					}					extends_ok=ObjectTypeDB::is_type(obj_A->get_type_name(),nc->get_name());				}				*dst=extends_ok;				ip+=4;			} continue;			case OPCODE_SET: {				CHECK_SPACE(3);				GET_VARIANT_PTR(dst,1);				GET_VARIANT_PTR(index,2);				GET_VARIANT_PTR(value,3);				bool valid;				dst->set(*index,*value,&valid);				if (!valid) {					String v = index->operator String();					if (v!="") {						v="'"+v+"'";					} else {						v="of type '"+_get_var_type(index)+"'";					}					err_text="Invalid set index "+v+" (on base: '"+_get_var_type(dst)+"').";					break;				}				ip+=4;			} continue;			case OPCODE_GET: {				CHECK_SPACE(3);				GET_VARIANT_PTR(src,1);				GET_VARIANT_PTR(index,2);				GET_VARIANT_PTR(dst,3);				bool valid;				*dst = src->get(*index,&valid);				if (!valid) {					String v = index->operator String();					if (v!="") {						v="'"+v+"'";					} else {						v="of type '"+_get_var_type(index)+"'";					}					err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"').";					break;				}				ip+=4;			} continue;			case OPCODE_SET_NAMED: {				CHECK_SPACE(3);				GET_VARIANT_PTR(dst,1);				GET_VARIANT_PTR(value,3);				int indexname = _code_ptr[ip+2];				ERR_BREAK(indexname<0 || indexname>=_global_names_count);				const StringName *index = &_global_names_ptr[indexname];				bool valid;				dst->set_named(*index,*value,&valid);				if (!valid) {					String err_type;					err_text="Invalid set index '"+String(*index)+"' (on base: '"+_get_var_type(dst)+"').";					break;				}				ip+=4;			} continue;			case OPCODE_GET_NAMED: {				CHECK_SPACE(3);				GET_VARIANT_PTR(src,1);				GET_VARIANT_PTR(dst,3);				int indexname = _code_ptr[ip+2];				ERR_BREAK(indexname<0 || indexname>=_global_names_count);				const StringName *index = &_global_names_ptr[indexname];				bool valid;				*dst = src->get_named(*index,&valid);				if (!valid) {					err_text="Invalid get index '"+index->operator String()+"' (on base: '"+_get_var_type(src)+"').";					break;				}				ip+=4;			} continue;			case OPCODE_ASSIGN: {				CHECK_SPACE(3);				GET_VARIANT_PTR(dst,1);				GET_VARIANT_PTR(src,2);				*dst = *src;				ip+=3;			} continue;			case OPCODE_ASSIGN_TRUE: {				CHECK_SPACE(2);				GET_VARIANT_PTR(dst,1);				*dst = true;				ip+=2;			} continue;			case OPCODE_ASSIGN_FALSE: {				CHECK_SPACE(2);				GET_VARIANT_PTR(dst,1);				*dst = false;				ip+=2;			} continue;			case OPCODE_CONSTRUCT: {				CHECK_SPACE(2);				Variant::Type t=Variant::Type(_code_ptr[ip+1]);				int argc=_code_ptr[ip+2];				CHECK_SPACE(argc+2);				Variant **argptrs = call_args;				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(v,3+i);					argptrs[i]=v;				}				GET_VARIANT_PTR(dst,3+argc);				Variant::CallError err;				*dst = Variant::construct(t,(const Variant**)argptrs,argc,err);				if (err.error!=Variant::CallError::CALL_OK) {					err_text=_get_call_error(err,"'"+Variant::get_type_name(t)+"' constructor",(const Variant**)argptrs);					break;				}				ip+=4+argc;				//construct a basic type			} continue;			case OPCODE_CONSTRUCT_ARRAY: {				CHECK_SPACE(1);				int argc=_code_ptr[ip+1];				Array array(true); //arrays are always shared				array.resize(argc);				CHECK_SPACE(argc+2);				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(v,2+i);					array[i]=*v;				}				GET_VARIANT_PTR(dst,2+argc);				*dst=array;				ip+=3+argc;			} continue;			case OPCODE_CONSTRUCT_DICTIONARY: {				CHECK_SPACE(1);				int argc=_code_ptr[ip+1];				Dictionary dict(true); //arrays are always shared				CHECK_SPACE(argc*2+2);				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(k,2+i*2+0);					GET_VARIANT_PTR(v,2+i*2+1);					dict[*k]=*v;				}				GET_VARIANT_PTR(dst,2+argc*2);				*dst=dict;				ip+=3+argc*2;			} continue;			case OPCODE_CALL_RETURN:			case OPCODE_CALL: {				CHECK_SPACE(4);				bool call_ret = _code_ptr[ip]==OPCODE_CALL_RETURN;				int argc=_code_ptr[ip+1];				GET_VARIANT_PTR(base,2);				int nameg=_code_ptr[ip+3];				ERR_BREAK(nameg<0 || nameg>=_global_names_count);				const StringName *methodname = &_global_names_ptr[nameg];				ERR_BREAK(argc<0);				ip+=4;				CHECK_SPACE(argc+1);				Variant **argptrs = call_args;				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(v,i);					argptrs[i]=v;				}				Variant::CallError err;				if (call_ret) {					GET_VARIANT_PTR(ret,argc);					*ret = base->call(*methodname,(const Variant**)argptrs,argc,err);				} else {					base->call(*methodname,(const Variant**)argptrs,argc,err);				}				if (err.error!=Variant::CallError::CALL_OK) {					String methodstr = *methodname;					String basestr = _get_var_type(base);					if (methodstr=="call") {						if (argc>=1) {							methodstr=String(*argptrs[0])+" (via call)";							if (err.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {								err.argument-=1;							}						}					}					err_text=_get_call_error(err,"function '"+methodstr+"' in base '"+basestr+"'",(const Variant**)argptrs);					break;				}				//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);				ip+=argc+1;			} continue;			case OPCODE_CALL_BUILT_IN: {				CHECK_SPACE(4);				GDFunctions::Function func = GDFunctions::Function(_code_ptr[ip+1]);				int argc=_code_ptr[ip+2];				ERR_BREAK(argc<0);				ip+=3;				CHECK_SPACE(argc+1);				Variant **argptrs = call_args;				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(v,i);					argptrs[i]=v;				}				GET_VARIANT_PTR(dst,argc);				Variant::CallError err;				GDFunctions::call(func,(const Variant**)argptrs,argc,*dst,err);				if (err.error!=Variant::CallError::CALL_OK) {					String methodstr = GDFunctions::get_func_name(func);					err_text=_get_call_error(err,"built-in function '"+methodstr+"'",(const Variant**)argptrs);					break;				}				ip+=argc+1;			} continue;			case OPCODE_CALL_SELF: {			} break;			case OPCODE_CALL_SELF_BASE: {				CHECK_SPACE(2);				int self_fun = _code_ptr[ip+1];#ifdef DEBUG_ENABLED				if (self_fun<0 || self_fun>=_global_names_count) {					err_text="compiler bug, function name not found";					break;				}#endif				const StringName *methodname = &_global_names_ptr[self_fun];				int argc=_code_ptr[ip+2];				CHECK_SPACE(2+argc+1);				Variant **argptrs = call_args;				for(int i=0;i<argc;i++) {					GET_VARIANT_PTR(v,i+3);					argptrs[i]=v;				}				GET_VARIANT_PTR(dst,argc+3);				const GDScript *gds = _script;				const Map<StringName,GDFunction>::Element *E=NULL;				while (gds->base.ptr()) {					gds=gds->base.ptr();					E=gds->member_functions.find(*methodname);					if (E)						break;				}				Variant::CallError err;				if (E) {					*dst=((GDFunction*)&E->get())->call(p_instance,(const Variant**)argptrs,argc,err);				} else if (gds->native.ptr()) {					if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) {						MethodBind *mb = ObjectTypeDB::get_method(gds->native->get_name(),*methodname);						if (!mb) {							err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;						} else {							*dst=mb->call(p_instance->owner,(const Variant**)argptrs,argc,err);						}					} else {						err.error=Variant::CallError::CALL_OK;					}				} else {					if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) {						err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;					} else {						err.error=Variant::CallError::CALL_OK;					}				}				if (err.error!=Variant::CallError::CALL_OK) {					String methodstr = *methodname;					err_text=_get_call_error(err,"function '"+methodstr+"'",(const Variant**)argptrs);					break;				}				ip+=4+argc;			} continue;			case OPCODE_JUMP: {				CHECK_SPACE(2);				int to = _code_ptr[ip+1];				ERR_BREAK(to<0 || to>_code_size);				ip=to;			} continue;			case OPCODE_JUMP_IF: {				CHECK_SPACE(3);				GET_VARIANT_PTR(test,1);				bool valid;				bool result = test->booleanize(valid);#ifdef DEBUG_ENABLED				if (!valid) {					err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type());					break;				}#endif				if (result) {					int to = _code_ptr[ip+2];					ERR_BREAK(to<0 || to>_code_size);					ip=to;					continue;				}				ip+=3;			} continue;			case OPCODE_JUMP_IF_NOT: {				CHECK_SPACE(3);				GET_VARIANT_PTR(test,1);				bool valid;				bool result = test->booleanize(valid);#ifdef DEBUG_ENABLED				if (!valid) {					err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type());					break;				}#endif				if (!result) {					int to = _code_ptr[ip+2];					ERR_BREAK(to<0 || to>_code_size);					ip=to;					continue;				}				ip+=3;			} continue;			case OPCODE_JUMP_TO_DEF_ARGUMENT: {				CHECK_SPACE(2);				ip=_default_arg_ptr[defarg];			} continue;			case OPCODE_RETURN: {				CHECK_SPACE(2);				GET_VARIANT_PTR(r,1);				retvalue=*r;				exit_ok=true;			} break;			case OPCODE_ITERATE_BEGIN: {				CHECK_SPACE(8); //space for this an regular iterate				GET_VARIANT_PTR(counter,1);				GET_VARIANT_PTR(container,2);				bool valid;				if (!container->iter_init(*counter,valid)) {					if (!valid) {						err_text="Unable to iterate on object of type  "+Variant::get_type_name(container->get_type())+"'.";						break;					}					int jumpto=_code_ptr[ip+3];					ERR_BREAK(jumpto<0 || jumpto>_code_size);					ip=jumpto;					continue;				}				GET_VARIANT_PTR(iterator,4);				*iterator=container->iter_get(*counter,valid);				if (!valid) {					err_text="Unable to obtain iterator object of type  "+Variant::get_type_name(container->get_type())+"'.";					break;				}				ip+=5; //skip regular iterate which is always next			} continue;			case OPCODE_ITERATE: {				CHECK_SPACE(4);				GET_VARIANT_PTR(counter,1);				GET_VARIANT_PTR(container,2);				bool valid;				if (!container->iter_next(*counter,valid)) {					if (!valid) {						err_text="Unable to iterate on object of type  "+Variant::get_type_name(container->get_type())+"' (type changed since first iteration?).";						break;					}					int jumpto=_code_ptr[ip+3];					ERR_BREAK(jumpto<0 || jumpto>_code_size);					ip=jumpto;					continue;				}				GET_VARIANT_PTR(iterator,4);				*iterator=container->iter_get(*counter,valid);				if (!valid) {					err_text="Unable to obtain iterator object of type  "+Variant::get_type_name(container->get_type())+"' (but was obtained on first iteration?).";					break;				}				ip+=5; //loop again			} continue;			case OPCODE_ASSERT: {				CHECK_SPACE(2);				GET_VARIANT_PTR(test,1);#ifdef DEBUG_ENABLED				bool valid;				bool result = test->booleanize(valid);				if (!valid) {					err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type());					break;				}				if (!result) {					err_text="Assertion failed.";					break;				}#endif				ip+=2;			} continue;			case OPCODE_LINE: {				CHECK_SPACE(2);				line=_code_ptr[ip+1];				ip+=2;				if (ScriptDebugger::get_singleton()) {			    // line					bool do_break=false;					if (ScriptDebugger::get_singleton()->get_lines_left()>0) {						if (ScriptDebugger::get_singleton()->get_depth()<=0)							ScriptDebugger::get_singleton()->set_lines_left( ScriptDebugger::get_singleton()->get_lines_left() -1 );						if (ScriptDebugger::get_singleton()->get_lines_left()<=0)							do_break=true;					}					if (ScriptDebugger::get_singleton()->is_breakpoint(line,source))						do_break=true;					if (do_break) {						GDScriptLanguage::get_singleton()->debug_break("Breakpoint",true);					}					ScriptDebugger::get_singleton()->line_poll();				}			} continue;			case OPCODE_END: {				exit_ok=true;				break;			} break;			default: {				err_text="Illegal opcode "+itos(_code_ptr[ip])+" at address "+itos(ip);			} break;		}		if (exit_ok)			break;		//error		// function, file, line, error, explanation		String err_file;		if (p_instance)			err_file=p_instance->script->path;		else if (_class)			err_file=_class->path;		if (err_file=="")			err_file="<built-in>";		String err_func = name;		if (p_instance && p_instance->script->name!="")			err_func=p_instance->script->name+"."+err_func;		int err_line=line;		if (err_text=="") {			err_text="Internal Script Error! - opcode #"+itos(last_opcode)+" (report please).";		}	if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {            // debugger break did not happen            _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data());        }		break;	}    if (ScriptDebugger::get_singleton())        GDScriptLanguage::get_singleton()->exit_function();	if (_stack_size) {		//free stack		for(int i=0;i<_stack_size;i++)			stack[i].~Variant();	}	return retvalue;}const int* GDFunction::get_code() const {	return _code_ptr;}int GDFunction::get_code_size() const{	return _code_size;}Variant GDFunction::get_constant(int p_idx) const {	ERR_FAIL_INDEX_V(p_idx,constants.size(),"<errconst>");	return constants[p_idx];}StringName GDFunction::get_global_name(int p_idx) const {	ERR_FAIL_INDEX_V(p_idx,global_names.size(),"<errgname>");	return global_names[p_idx];}int GDFunction::get_default_argument_count() const {	return default_arguments.size();}int GDFunction::get_default_argument_addr(int p_arg) const{	ERR_FAIL_INDEX_V(p_arg,default_arguments.size(),-1);	return default_arguments[p_arg];}StringName GDFunction::get_name() const {	return name;}int GDFunction::get_max_stack_size() const {	return _stack_size;}struct _GDFKC {    int order;    List<int> pos;};struct _GDFKCS {    int order;    StringName id;    int pos;    bool operator<(const _GDFKCS &p_r) const {        return order<p_r.order;    }};void GDFunction::debug_get_stack_member_state(int p_line,List<Pair<StringName,int> > *r_stackvars) const {    int oc=0;    Map<StringName,_GDFKC> sdmap;    for( const List<StackDebug>::Element *E=stack_debug.front();E;E=E->next()) {        const StackDebug &sd=E->get();        if (sd.line>p_line)            break;        if (sd.added) {            if (!sdmap.has(sd.identifier)) {                _GDFKC d;                d.order=oc++;                d.pos.push_back(sd.pos);                sdmap[sd.identifier]=d;            } else {                sdmap[sd.identifier].pos.push_back(sd.pos);            }        } else {            ERR_CONTINUE(!sdmap.has(sd.identifier));            sdmap[sd.identifier].pos.pop_back();            if (sdmap[sd.identifier].pos.empty())                sdmap.erase(sd.identifier);        }    }    List<_GDFKCS> stackpositions;    for(Map<StringName,_GDFKC>::Element *E=sdmap.front();E;E=E->next() ) {        _GDFKCS spp;        spp.id=E->key();        spp.order=E->get().order;        spp.pos=E->get().pos.back()->get();        stackpositions.push_back(spp);    }    stackpositions.sort();    for(List<_GDFKCS>::Element *E=stackpositions.front();E;E=E->next()) {        Pair<StringName,int> p;        p.first=E->get().id;        p.second=E->get().pos;        r_stackvars->push_back(p);    }}#if 0void GDFunction::clear() {	name=StringName();	constants.clear();	_stack_size=0;	code.clear();	_constants_ptr=NULL;	_constant_count=0;	_global_names_ptr=NULL;	_global_names_count=0;	_code_ptr=NULL;	_code_size=0;}#endifGDFunction::GDFunction() {	_stack_size=0;	_call_size=0;	name="<anonymous>";}GDNativeClass::GDNativeClass(const StringName& p_name) {	name=p_name;}/*void GDNativeClass::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount){}*/bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const {	bool ok;	int v = ObjectTypeDB::get_integer_constant(name, p_name, &ok);	if (ok) {		r_ret=v;		return true;	} else {		return false;	}}void GDNativeClass::_bind_methods() {	ObjectTypeDB::bind_method(_MD("new"),&GDNativeClass::_new);}Variant GDNativeClass::_new() {	Object *o = instance();	if (!o) {		ERR_EXPLAIN("Class type: '"+String(name)+"' is not instantiable.");		ERR_FAIL_COND_V(!o,Variant());	}	Reference *ref = o->cast_to<Reference>();	if (ref) {		return REF(ref);	} else {		return o;	}}Object *GDNativeClass::instance() {	return ObjectTypeDB::instance(name);}GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref) {	/* STEP 1, CREATE */	GDInstance* instance = memnew( GDInstance );	instance->base_ref=p_isref;	instance->members.resize(member_indices.size());	instance->script=Ref<GDScript>(this);	instance->owner=p_owner;	instance->owner->set_script_instance(instance);	/* STEP 2, INITIALIZE AND CONSRTUCT */	instances.insert(instance->owner);	Variant::CallError err;	initializer->call(instance,p_args,p_argcount,err);	if (err.error!=Variant::CallError::CALL_OK) {		instance->script=Ref<GDScript>();		instances.erase(p_owner);		memdelete(instance);		ERR_FAIL_COND_V(err.error!=Variant::CallError::CALL_OK, NULL); //error consrtucting	}	//@TODO make thread safe	return instance;}Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError& r_error) {	/* STEP 1, CREATE */	r_error.error=Variant::CallError::CALL_OK;	REF ref;	Object *owner=NULL;	GDScript *_baseptr=this;	while (_baseptr->_base) {		_baseptr=_baseptr->_base;	}	if (_baseptr->native.ptr()) {		owner=_baseptr->native->instance();	} else {		owner=memnew( Reference ); //by default, no base means use reference	}	Reference *r=owner->cast_to<Reference>();	if (r) {		ref=REF(r);	}	GDInstance* instance = _create_instance(p_args,p_argcount,owner,r!=NULL);	if (!instance) {		if (ref.is_null()) {			memdelete(owner); //no owner, sorry		}		return Variant();	}	if (ref.is_valid()) {				return ref;	} else {		return owner;	}}bool GDScript::can_instance() const {	return valid; //any script in GDscript can instance}StringName GDScript::get_instance_base_type() const {	if (native.is_valid())		return native->get_name();	if (base.is_valid())		return base->get_instance_base_type();	return StringName();}struct _GDScriptMemberSort {	int index;	StringName name;	_FORCE_INLINE_ bool operator<(const _GDScriptMemberSort& p_member) const { return index < p_member.index; }};#ifdef TOOLS_ENABLEDvoid GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {	placeholders.erase(p_placeholder);}void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {	List<PropertyInfo> plist;	GDScript *scr=this;	Map<StringName,Variant> default_values;	while(scr) {		Vector<_GDScriptMemberSort> msort;		for(Map<StringName,PropertyInfo>::Element *E=scr->member_info.front();E;E=E->next()) {			_GDScriptMemberSort ms;			ERR_CONTINUE(!scr->member_indices.has(E->key()));			ms.index=scr->member_indices[E->key()];			ms.name=E->key();			msort.push_back(ms);		}		msort.sort();		msort.invert();		for(int i=0;i<msort.size();i++) {			plist.push_front(scr->member_info[msort[i].name]);			if (scr->member_default_values.has(msort[i].name))				default_values[msort[i].name]=scr->member_default_values[msort[i].name];			else {				Variant::CallError err;				default_values[msort[i].name]=Variant::construct(scr->member_info[msort[i].name].type,NULL,0,err);			}		}		scr=scr->_base;	}	p_placeholder->update(plist,default_values);}#endifScriptInstance* GDScript::instance_create(Object *p_this) {	if (!tool && !ScriptServer::is_scripting_enabled()) {#ifdef TOOLS_ENABLED		//instance a fake script for editing the values		//plist.invert();		/*print_line("CREATING PLACEHOLDER");		for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {			print_line(E->get().name);		}*/		PlaceHolderScriptInstance *si = memnew( PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(),Ref<Script>(this),p_this) );		placeholders.insert(si);		_update_placeholder(si);		return si;#else		return NULL;#endif	}	GDScript *top=this;	while(top->_base)		top=top->_base;	if (top->native.is_valid()) {		if (!ObjectTypeDB::is_type(p_this->get_type_name(),top->native->get_name())) {			if (ScriptDebugger::get_singleton()) {				GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'");			}			ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'");			ERR_FAIL_V(NULL);		}	}	return _create_instance(NULL,0,p_this,p_this->cast_to<Reference>());}bool GDScript::instance_has(const Object *p_this) const {	return instances.has((Object*)p_this);}bool GDScript::has_source_code() const {	return source!="";}String GDScript::get_source_code() const {	return source;}void GDScript::set_source_code(const String& p_code) {	source=p_code;}void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) {	p_sc->path=p_path;	for(Map<StringName,Ref<GDScript> >::Element *E=p_sc->subclasses.front();E;E=E->next()) {		_set_subclass_path(E->get(),p_path);	}}Error GDScript::reload() {	ERR_FAIL_COND_V(instances.size(),ERR_ALREADY_IN_USE);	String basedir=path;	if (basedir=="")		basedir=get_path();	if (basedir!="")		basedir=basedir.get_base_dir();	valid=false;	GDParser parser;	Error err = parser.parse(source,basedir);	if (err) {		if (ScriptDebugger::get_singleton()) {			GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error());		}		_err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data());		ERR_FAIL_V(ERR_PARSE_ERROR);	}	GDCompiler compiler;	err = compiler.compile(&parser,this);	if (err) {		if (ScriptDebugger::get_singleton()) {			GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),compiler.get_error_line(),"Parser Error: "+compiler.get_error());		}		_err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),compiler.get_error_line(),("Compile Error: "+compiler.get_error()).utf8().get_data());		ERR_FAIL_V(ERR_COMPILATION_FAILED);	}	valid=true;	for(Map<StringName,Ref<GDScript> >::Element *E=subclasses.front();E;E=E->next()) {		_set_subclass_path(E->get(),path);	}#ifdef TOOLS_ENABLED	for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {		_update_placeholder(E->get());	}#endif	return OK;}String GDScript::get_node_type() const {	return ""; // ?}ScriptLanguage *GDScript::get_language() const {	return GDScriptLanguage::get_singleton();}Variant GDScript::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {	GDScript *top=this;	while(top) {		Map<StringName,GDFunction>::Element *E=top->member_functions.find(p_method);		if (E) {			if (!E->get().is_static()) {				WARN_PRINT(String("Can't call non-static function: '"+String(p_method)+"' in script.").utf8().get_data());			}			return E->get().call(NULL,p_args,p_argcount,r_error);		}		top=top->_base;	}	//none found, regular	return Script::call(p_method,p_args,p_argcount,r_error);}bool GDScript::_get(const StringName& p_name,Variant &r_ret) const {	{		const GDScript *top=this;		while(top) {			{				const Map<StringName,Variant>::Element *E=top->constants.find(p_name);				if (E) {					r_ret= E->get();					return true;				}			}			{				const Map<StringName,Ref<GDScript> >::Element *E=subclasses.find(p_name);				if (E) {					r_ret=E->get();					return true;				}			}			top=top->_base;		}		if (p_name==GDScriptLanguage::get_singleton()->strings._script_source) {			r_ret=get_source_code();			return true;		}	}	return false;}bool GDScript::_set(const StringName& p_name, const Variant& p_value) {	if (p_name==GDScriptLanguage::get_singleton()->strings._script_source) {		set_source_code(p_value);		reload();	} else		return false;	return true;}void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {	p_properties->push_back( PropertyInfo(Variant::STRING,"script/source",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) );}void GDScript::_bind_methods() {	ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new"));	}Error GDScript::load_byte_code(const String& p_path) {	Vector<uint8_t> bytecode = FileAccess::get_file_as_array(p_path);	ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR);	path=p_path;	String basedir=path;	if (basedir=="")		basedir=get_path();	if (basedir!="")		basedir=basedir.get_base_dir();	valid=false;	GDParser parser;	Error err = parser.parse_bytecode(bytecode,basedir);	if (err) {		_err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data());		ERR_FAIL_V(ERR_PARSE_ERROR);	}	GDCompiler compiler;	err = compiler.compile(&parser,this);	if (err) {		_err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),compiler.get_error_line(),("Compile Error: "+compiler.get_error()).utf8().get_data());		ERR_FAIL_V(ERR_COMPILATION_FAILED);	}	valid=true;	for(Map<StringName,Ref<GDScript> >::Element *E=subclasses.front();E;E=E->next()) {		_set_subclass_path(E->get(),path);	}	return OK;}Error GDScript::load_source_code(const String& p_path) {	DVector<uint8_t> sourcef;	Error err;	FileAccess *f=FileAccess::open(p_path,FileAccess::READ,&err);	if (err) {		ERR_FAIL_COND_V(err,err);	}	int len = f->get_len();	sourcef.resize(len+1);	DVector<uint8_t>::Write w = sourcef.write();	int r = f->get_buffer(w.ptr(),len);	f->close();	memdelete(f);	ERR_FAIL_COND_V(r!=len,ERR_CANT_OPEN);	w[len]=0;	String s;	if (s.parse_utf8((const char*)w.ptr())) {		ERR_EXPLAIN("Script '"+p_path+"' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");		ERR_FAIL_V(ERR_INVALID_DATA);	}	source=s;	path=p_path;	return OK;}const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const {	return member_functions;}StringName GDScript::debug_get_member_by_index(int p_idx) const {	for(const Map<StringName,int>::Element *E=member_indices.front();E;E=E->next()) {		if (E->get()==p_idx)			return E->key();	}	return "<error>";}Ref<GDScript> GDScript::get_base() const {	return base;}GDScript::GDScript() {	valid=false;	subclass_count=0;	initializer=NULL;	_base=NULL;	_owner=NULL;	tool=false;}////////////////////////////////         INSTANCE         ////////////////////////////////bool GDInstance::set(const StringName& p_name, const Variant& p_value) {	//member	{		const Map<StringName,int>::Element *E = script->member_indices.find(p_name);		if (E) {			members[E->get()]=p_value;			return true;		}	}	GDScript *sptr=script.ptr();	while(sptr) {		 Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);		if (E) {			Variant name=p_name;			const Variant *args[2]={&name,&p_value};			Variant::CallError err;			Variant ret = E->get().call(this,(const Variant**)args,2,err);			if (err.error==Variant::CallError::CALL_OK && ret.get_type()==Variant::BOOL && ret.operator bool())				return true;		}		sptr = sptr->_base;	}	return false;}bool GDInstance::get(const StringName& p_name, Variant &r_ret) const {	const GDScript *sptr=script.ptr();	while(sptr) {		{			const Map<StringName,int>::Element *E = script->member_indices.find(p_name);			if (E) {				r_ret=members[E->get()];				return true; //index found			}		}		{			const Map<StringName,Variant>::Element *E = script->constants.find(p_name);			if (E) {				r_ret=E->get();				return true; //index found			}		}		{			const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);			if (E) {				Variant name=p_name;				const Variant *args[1]={&name};				Variant::CallError err;				Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),(const Variant**)args,1,err);				if (err.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {					r_ret=ret;					return true;				}			}		}		sptr = sptr->_base;	}	return false;}void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const {	// exported members, not doen yet!	const GDScript *sptr=script.ptr();	List<PropertyInfo> props;	while(sptr) {		const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);		if (E) {			Variant::CallError err;			Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),NULL,0,err);			if (err.error==Variant::CallError::CALL_OK) {				if (ret.get_type()!=Variant::ARRAY) {					ERR_EXPLAIN("Wrong type for _get_property list, must be an array of dictionaries.");					ERR_FAIL();				}				Array arr = ret;				for(int i=0;i<arr.size();i++) {					Dictionary d = arr[i];					ERR_CONTINUE(!d.has("name"));					ERR_CONTINUE(!d.has("type"));					PropertyInfo pinfo;					pinfo.type = Variant::Type( d["type"].operator int());					ERR_CONTINUE(pinfo.type<0 || pinfo.type>=Variant::VARIANT_MAX );					pinfo.name = d["name"];					ERR_CONTINUE(pinfo.name=="");					if (d.has("hint"))						pinfo.hint=PropertyHint(d["hint"].operator int());					if (d.has("hint_string"))						pinfo.hint_string=d["hint_string"];					if (d.has("usage"))						pinfo.usage=d["usage"];					props.push_back(pinfo);				}			}		}		//instance a fake script for editing the values		Vector<_GDScriptMemberSort> msort;		for(Map<StringName,PropertyInfo>::Element *E=sptr->member_info.front();E;E=E->next()) {			_GDScriptMemberSort ms;			ERR_CONTINUE(!sptr->member_indices.has(E->key()));			ms.index=sptr->member_indices[E->key()];			ms.name=E->key();			msort.push_back(ms);		}		msort.sort();		msort.invert();		for(int i=0;i<msort.size();i++) {			props.push_front(sptr->member_info[msort[i].name]);		}#if 0		if (sptr->member_functions.has("_get_property_list")) {			Variant::CallError err;			GDFunction *f = const_cast<GDFunction*>(&sptr->member_functions["_get_property_list"]);			Variant plv = f->call(const_cast<GDInstance*>(this),NULL,0,err);			if (plv.get_type()!=Variant::ARRAY) {				ERR_PRINT("_get_property_list: expected array returned");			} else {				Array pl=plv;				for(int i=0;i<pl.size();i++) {					Dictionary p = pl[i];					PropertyInfo pinfo;					if (!p.has("name")) {						ERR_PRINT("_get_property_list: expected 'name' key of type string.")						continue;					}					if (!p.has("type")) {						ERR_PRINT("_get_property_list: expected 'type' key of type integer.")						continue;					}					pinfo.name=p["name"];					pinfo.type=Variant::Type(int(p["type"]));					if (p.has("hint"))						pinfo.hint=PropertyHint(int(p["hint"]));					if (p.has("hint_string"))						pinfo.hint_string=p["hint_string"];					if (p.has("usage"))						pinfo.usage=p["usage"];					props.push_back(pinfo);				}			}		}#endif		sptr = sptr->_base;	}	//props.invert();	for (List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {		p_properties->push_back(E->get());	}}void GDInstance::get_method_list(List<MethodInfo> *p_list) const {	const GDScript *sptr=script.ptr();	while(sptr) {		for (Map<StringName,GDFunction>::Element *E = sptr->member_functions.front();E;E=E->next()) {			MethodInfo mi;			mi.name=E->key();			for(int i=0;i<E->get().get_argument_count();i++)				mi.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i)));			p_list->push_back(mi);		}		sptr = sptr->_base;	}}bool GDInstance::has_method(const StringName& p_method) const {	const GDScript *sptr=script.ptr();	while(sptr) {		const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method);		if (E)			return true;		sptr = sptr->_base;	}	return false;}Variant GDInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {	//printf("calling %ls:%i method %ls\n", script->get_path().c_str(), -1, String(p_method).c_str());	GDScript *sptr=script.ptr();	while(sptr) {		Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method);		if (E) {			return E->get().call(this,p_args,p_argcount,r_error);		}		sptr = sptr->_base;	}	r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;	return Variant();}void GDInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount) {	GDScript *sptr=script.ptr();	Variant::CallError ce;	while(sptr) {		Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method);		if (E) {			E->get().call(this,p_args,p_argcount,ce);		}		sptr = sptr->_base;	}}void GDInstance::_ml_call_reversed(GDScript *sptr,const StringName& p_method,const Variant** p_args,int p_argcount) {	if (sptr->_base)		_ml_call_reversed(sptr->_base,p_method,p_args,p_argcount);	Variant::CallError ce;	Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method);	if (E) {		E->get().call(this,p_args,p_argcount,ce);	}}void GDInstance::call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount) {	if (script.ptr()) {		_ml_call_reversed(script.ptr(),p_method,p_args,p_argcount);	}}void GDInstance::notification(int p_notification) {	//notification is not virutal, it gets called at ALL levels just like in C.	Variant value=p_notification;	const Variant *args[1]={&value };	GDScript *sptr=script.ptr();	while(sptr) {		Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);		if (E) {			Variant::CallError err;			E->get().call(this,args,1,err);			if (err.error!=Variant::CallError::CALL_OK) {				//print error about notification call			}		}		sptr = sptr->_base;	}}Ref<Script> GDInstance::get_script() const {	return script;}ScriptLanguage *GDInstance::get_language() {	return GDScriptLanguage::get_singleton();}GDInstance::GDInstance() {	owner=NULL;	base_ref=false;}GDInstance::~GDInstance() {	if (script.is_valid() && owner) {		script->instances.erase(owner);	}}/************* SCRIPT LANGUAGE **************//************* SCRIPT LANGUAGE **************//************* SCRIPT LANGUAGE **************//************* SCRIPT LANGUAGE **************//************* SCRIPT LANGUAGE **************/GDScriptLanguage *GDScriptLanguage::singleton=NULL;String GDScriptLanguage::get_name() const {	return "GDScript";}/* LANGUAGE FUNCTIONS */void GDScriptLanguage::_add_global(const StringName& p_name,const Variant& p_value) {	if (globals.has(p_name)) {		//overwrite existing		global_array[globals[p_name]]=p_value;		return;	}	globals[p_name]=global_array.size();	global_array.push_back(p_value);	_global_array=global_array.ptr();}void GDScriptLanguage::init() {	//populate global constants	int gcc=GlobalConstants::get_global_constant_count();	for(int i=0;i<gcc;i++) {		_add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)),GlobalConstants::get_global_constant_value(i));	}	_add_global(StaticCString::create("PI"),Math_PI);	//populate native classes	List<String> class_list;	ObjectTypeDB::get_type_list(&class_list);	for(List<String>::Element *E=class_list.front();E;E=E->next()) {		StringName n = E->get();		String s = String(n);		if (s.begins_with("_"))			n=s.substr(1,s.length());		if (globals.has(n))			continue;		Ref<GDNativeClass> nc = memnew( GDNativeClass(E->get()) );		_add_global(n,nc);	}	//populate singletons	List<Globals::Singleton> singletons;	Globals::get_singleton()->get_singletons(&singletons);	for(List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) {		_add_global(E->get().name,E->get().ptr);	}}String GDScriptLanguage::get_type() const {	return "GDScript";}String GDScriptLanguage::get_extension() const {	return "gd";}Error GDScriptLanguage::execute_file(const String& p_path)  {	// ??	return OK;}void GDScriptLanguage::finish()  {}void GDScriptLanguage::frame() {//	print_line("calls: "+itos(calls));	calls=0;}/* EDITOR FUNCTIONS */void GDScriptLanguage::get_reserved_words(List<String> *p_words) const  {	static const char *_reserved_words[]={		"break",		"class",		"continue",		"const",		"else",		"elif",		"enum",		"extends"	,		"for"	,		"func"	,		"if"	,		"in"	,		"varl",		"null"	,		"return"	,		"self"	,		"while"	,		"true"	,		"false"	,		"tool",		"var",		"pass",		"and",		"or",		"export",	0};	const char **w=_reserved_words;	while (*w) {		p_words->push_back(*w);		w++;	}	for(int i=0;i<GDFunctions::FUNC_MAX;i++) {		p_words->push_back(GDFunctions::get_func_name(GDFunctions::Function(i)));	}}GDScriptLanguage::GDScriptLanguage() {	calls=0;	ERR_FAIL_COND(singleton);	singleton=this;	strings._init = StaticCString::create("_init");	strings._notification = StaticCString::create("_notification");	strings._set= StaticCString::create("_set");	strings._get= StaticCString::create("_get");	strings._get_property_list= StaticCString::create("_get_property_list");	strings._script_source=StaticCString::create("script/source");	_debug_parse_err_line=-1;	_debug_parse_err_file="";    _debug_call_stack_pos=0;    int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024);    if (ScriptDebugger::get_singleton()) {        //debugging enabled!	_debug_max_call_stack = dmcs;        if (_debug_max_call_stack<1024)            _debug_max_call_stack=1024;	_call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 );    } else {        _debug_max_call_stack=0;        _call_stack=NULL;    }}GDScriptLanguage::~GDScriptLanguage() {    if (_call_stack)  {        memdelete_arr(_call_stack);    }    singleton=NULL;}/*************** RESOURCE ***************/RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) {	GDScript *script = memnew( GDScript );	Ref<GDScript> scriptres(script);	if (p_path.ends_with(".gdc")) {		script->set_script_path(p_original_path); // script needs this.		script->set_path(p_original_path);		Error err = script->load_byte_code(p_path);		if (err!=OK) {			ERR_FAIL_COND_V(err!=OK, RES());		}	} else {		Error err = script->load_source_code(p_path);		if (err!=OK) {			ERR_FAIL_COND_V(err!=OK, RES());		}		script->set_script_path(p_original_path); // script needs this.		script->set_path(p_original_path);		//script->set_name(p_path.get_file());		script->reload();	}	return scriptres;}void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {	p_extensions->push_back("gd");	p_extensions->push_back("gdc");}bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {	return (p_type=="Script" || p_type=="GDScript");}String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {	String el = p_path.extension().to_lower();	if (el=="gd" || el=="gdc")		return "GDScript";	return "";}Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {	Ref<GDScript> sqscr = p_resource;	ERR_FAIL_COND_V(sqscr.is_null(),ERR_INVALID_PARAMETER);	String source = sqscr->get_source_code();	Error err;	FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err);	if (err) {		ERR_FAIL_COND_V(err,err);	}	file->store_string(source);	file->close();	memdelete(file);	return OK;}void ResourceFormatSaverGDScript::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {	if (p_resource->cast_to<GDScript>()) {		p_extensions->push_back("gd");	}}bool ResourceFormatSaverGDScript::recognize(const RES& p_resource) const {	return p_resource->cast_to<GDScript>()!=NULL;}
 |