2017-03-05 14:47:28 +00:00
/*************************************************************************/
2017-11-16 17:38:18 +00:00
/* gdscript_function.cpp */
2017-03-05 14:47:28 +00:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2017-03-05 14:47:28 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2017-03-05 14:47:28 +00:00
/* */
/* 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. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2017-11-16 17:38:18 +00:00
# include "gdscript_function.h"
2017-03-05 14:47:28 +00:00
2017-11-16 17:38:18 +00:00
# include "gdscript.h"
2016-06-01 01:28:27 +00:00
2017-11-16 17:38:18 +00:00
const int * GDScriptFunction : : get_code ( ) const {
2016-06-01 01:28:27 +00:00
return _code_ptr ;
}
2020-05-14 12:29:06 +00:00
2017-11-16 17:38:18 +00:00
int GDScriptFunction : : get_code_size ( ) const {
2016-06-01 01:28:27 +00:00
return _code_size ;
}
2017-11-16 17:38:18 +00:00
Variant GDScriptFunction : : get_constant ( int p_idx ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_idx , constants . size ( ) , " <errconst> " ) ;
2016-06-01 01:28:27 +00:00
return constants [ p_idx ] ;
}
2017-11-16 17:38:18 +00:00
StringName GDScriptFunction : : get_global_name ( int p_idx ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_idx , global_names . size ( ) , " <errgname> " ) ;
2016-06-01 01:28:27 +00:00
return global_names [ p_idx ] ;
}
2017-11-16 17:38:18 +00:00
int GDScriptFunction : : get_default_argument_count ( ) const {
2018-07-25 14:41:27 +00:00
return _default_arg_count ;
2016-06-01 01:28:27 +00:00
}
2020-05-14 12:29:06 +00:00
2017-11-16 17:38:18 +00:00
int GDScriptFunction : : get_default_argument_addr ( int p_idx ) const {
2017-08-12 16:52:50 +00:00
ERR_FAIL_INDEX_V ( p_idx , default_arguments . size ( ) , - 1 ) ;
return default_arguments [ p_idx ] ;
2016-06-01 01:28:27 +00:00
}
2018-05-30 02:16:54 +00:00
GDScriptDataType GDScriptFunction : : get_return_type ( ) const {
return return_type ;
}
GDScriptDataType GDScriptFunction : : get_argument_type ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , argument_types . size ( ) , GDScriptDataType ( ) ) ;
return argument_types [ p_idx ] ;
}
2017-11-16 17:38:18 +00:00
StringName GDScriptFunction : : get_name ( ) const {
2016-06-01 01:28:27 +00:00
return name ;
}
2017-11-16 17:38:18 +00:00
int GDScriptFunction : : get_max_stack_size ( ) const {
2016-06-01 01:28:27 +00:00
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 {
2017-03-05 15:44:50 +00:00
return order < p_r . order ;
2016-06-01 01:28:27 +00:00
}
} ;
2020-03-17 06:33:00 +00:00
void GDScriptFunction : : debug_get_stack_member_state ( int p_line , List < Pair < StringName , int > > * r_stackvars ) const {
2017-03-05 15:44:50 +00:00
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 ( ) ;
2020-05-14 14:41:43 +00:00
if ( sd . line > p_line ) {
2016-06-01 01:28:27 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2016-06-01 01:28:27 +00:00
if ( sd . added ) {
if ( ! sdmap . has ( sd . identifier ) ) {
_GDFKC d ;
2017-03-05 15:44:50 +00:00
d . order = oc + + ;
2016-06-01 01:28:27 +00:00
d . pos . push_back ( sd . pos ) ;
2017-03-05 15:44:50 +00:00
sdmap [ sd . identifier ] = d ;
2016-06-01 01:28:27 +00:00
} else {
sdmap [ sd . identifier ] . pos . push_back ( sd . pos ) ;
}
} else {
ERR_CONTINUE ( ! sdmap . has ( sd . identifier ) ) ;
sdmap [ sd . identifier ] . pos . pop_back ( ) ;
2020-05-14 14:41:43 +00:00
if ( sdmap [ sd . identifier ] . pos . empty ( ) ) {
2016-06-01 01:28:27 +00:00
sdmap . erase ( sd . identifier ) ;
2020-05-14 14:41:43 +00:00
}
2016-06-01 01:28:27 +00:00
}
}
List < _GDFKCS > stackpositions ;
2017-03-05 15:44:50 +00:00
for ( Map < StringName , _GDFKC > : : Element * E = sdmap . front ( ) ; E ; E = E - > next ( ) ) {
2016-06-01 01:28:27 +00:00
_GDFKCS spp ;
2017-03-05 15:44:50 +00:00
spp . id = E - > key ( ) ;
spp . order = E - > get ( ) . order ;
spp . pos = E - > get ( ) . pos . back ( ) - > get ( ) ;
2016-06-01 01:28:27 +00:00
stackpositions . push_back ( spp ) ;
}
stackpositions . sort ( ) ;
2017-03-05 15:44:50 +00:00
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 ;
2016-06-01 01:28:27 +00:00
r_stackvars - > push_back ( p ) ;
}
}
2020-11-13 13:31:14 +00:00
GDScriptFunction : : GDScriptFunction ( ) {
2017-03-05 15:44:50 +00:00
name = " <anonymous> " ;
2016-06-01 01:28:27 +00:00
# ifdef DEBUG_ENABLED
2020-02-26 10:28:13 +00:00
{
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
GDScriptLanguage : : get_singleton ( ) - > function_list . add ( & function_list ) ;
2016-06-01 01:28:27 +00:00
}
# endif
}
2017-11-16 17:38:18 +00:00
GDScriptFunction : : ~ GDScriptFunction ( ) {
2016-06-01 01:28:27 +00:00
# ifdef DEBUG_ENABLED
2020-02-26 10:28:13 +00:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
GDScriptLanguage : : get_singleton ( ) - > function_list . remove ( & function_list ) ;
2016-06-01 01:28:27 +00:00
# endif
}
/////////////////////
2020-02-19 19:27:19 +00:00
Variant GDScriptFunctionState : : _signal_callback ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2016-06-01 01:28:27 +00:00
Variant arg ;
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-06-01 01:28:27 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount = = 0 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2016-06-01 01:28:27 +00:00
return Variant ( ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_argcount = = 1 ) {
2016-06-01 01:28:27 +00:00
//noooneee
2017-03-05 15:44:50 +00:00
} else if ( p_argcount = = 2 ) {
arg = * p_args [ 0 ] ;
2016-06-01 01:28:27 +00:00
} else {
Array extra_args ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_argcount - 1 ; i + + ) {
2016-06-01 01:28:27 +00:00
extra_args . push_back ( * p_args [ i ] ) ;
}
2017-03-05 15:44:50 +00:00
arg = extra_args ;
2016-06-01 01:28:27 +00:00
}
2017-11-16 17:38:18 +00:00
Ref < GDScriptFunctionState > self = * p_args [ p_argcount - 1 ] ;
2016-06-01 01:28:27 +00:00
if ( self . is_null ( ) ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = p_argcount - 1 ;
r_error . expected = Variant : : OBJECT ;
2016-06-01 01:28:27 +00:00
return Variant ( ) ;
}
2019-07-17 20:47:00 +00:00
return resume ( arg ) ;
2016-06-01 01:28:27 +00:00
}
2017-11-16 17:38:18 +00:00
bool GDScriptFunctionState : : is_valid ( bool p_extended_check ) const {
2020-05-14 14:41:43 +00:00
if ( function = = nullptr ) {
2017-05-17 12:47:17 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2017-05-17 12:47:17 +00:00
if ( p_extended_check ) {
2020-05-05 10:53:05 +00:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
// Script gone?
if ( ! scripts_list . in_list ( ) ) {
2017-05-17 12:47:17 +00:00
return false ;
2020-04-29 11:38:00 +00:00
}
2020-05-05 10:53:05 +00:00
// Class instance gone? (if not static function)
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 11:38:00 +00:00
return false ;
}
2017-05-17 12:47:17 +00:00
}
2016-06-01 01:28:27 +00:00
2017-05-17 12:47:17 +00:00
return true ;
2016-06-01 01:28:27 +00:00
}
2017-11-16 17:38:18 +00:00
Variant GDScriptFunctionState : : resume ( const Variant & p_arg ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! function , Variant ( ) ) ;
2020-05-05 10:53:05 +00:00
{
MutexLock lock ( GDScriptLanguage : : singleton - > lock ) ;
if ( ! scripts_list . in_list ( ) ) {
2018-11-25 11:38:12 +00:00
# ifdef DEBUG_ENABLED
2020-05-01 22:14:56 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " Resumed function ' " + state . function_name + " ()' after await, but script is gone. At script: " + state . script_path + " : " + itos ( state . line ) ) ;
2020-04-29 11:38:00 +00:00
# else
2020-05-05 10:53:05 +00:00
return Variant ( ) ;
2020-04-29 11:38:00 +00:00
# endif
2020-05-05 10:53:05 +00:00
}
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 11:38:00 +00:00
# ifdef DEBUG_ENABLED
2020-05-01 22:14:56 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " Resumed function ' " + state . function_name + " ()' after await, but class instance is gone. At script: " + state . script_path + " : " + itos ( state . line ) ) ;
2018-11-25 11:38:12 +00:00
# else
2020-05-05 10:53:05 +00:00
return Variant ( ) ;
2016-06-30 00:06:16 +00:00
# endif
2020-05-05 10:53:05 +00:00
}
// Do these now to avoid locking again after the call
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2018-11-25 11:38:12 +00:00
}
2016-06-01 01:28:27 +00:00
2017-03-05 15:44:50 +00:00
state . result = p_arg ;
2020-02-19 19:27:19 +00:00
Callable : : CallError err ;
2020-04-01 23:20:12 +00:00
Variant ret = function - > call ( nullptr , nullptr , 0 , err , & state ) ;
2017-06-23 00:29:23 +00:00
bool completed = true ;
2017-11-16 17:38:18 +00:00
// If the return value is a GDScriptFunctionState reference,
2020-05-01 22:14:56 +00:00
// then the function did awaited again after resuming.
2017-06-23 00:29:23 +00:00
if ( ret . is_ref ( ) ) {
2017-11-16 17:38:18 +00:00
GDScriptFunctionState * gdfs = Object : : cast_to < GDScriptFunctionState > ( ret ) ;
2018-03-14 15:42:13 +00:00
if ( gdfs & & gdfs - > function = = function ) {
2017-06-23 00:29:23 +00:00
completed = false ;
2018-06-28 15:40:11 +00:00
gdfs - > first_state = first_state . is_valid ( ) ? first_state : Ref < GDScriptFunctionState > ( this ) ;
2018-03-14 15:42:13 +00:00
}
2017-06-23 00:29:23 +00:00
}
2020-04-01 23:20:12 +00:00
function = nullptr ; //cleaned up;
2017-03-05 15:44:50 +00:00
state . result = Variant ( ) ;
2017-06-23 00:29:23 +00:00
if ( completed ) {
2018-06-28 15:40:11 +00:00
if ( first_state . is_valid ( ) ) {
first_state - > emit_signal ( " completed " , ret ) ;
} else {
emit_signal ( " completed " , ret ) ;
2018-03-14 15:42:13 +00:00
}
2019-05-10 19:38:48 +00:00
# ifdef DEBUG_ENABLED
2020-05-14 14:41:43 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2019-05-10 19:38:48 +00:00
GDScriptLanguage : : get_singleton ( ) - > exit_function ( ) ;
2020-05-14 14:41:43 +00:00
}
2019-05-10 19:38:48 +00:00
# endif
2017-06-23 00:29:23 +00:00
}
2016-06-01 01:28:27 +00:00
return ret ;
}
2020-05-05 10:53:05 +00:00
void GDScriptFunctionState : : _clear_stack ( ) {
if ( state . stack_size ) {
Variant * stack = ( Variant * ) state . stack . ptr ( ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < state . stack_size ; i + + ) {
2020-05-05 10:53:05 +00:00
stack [ i ] . ~ Variant ( ) ;
2020-05-14 14:41:43 +00:00
}
2020-05-05 10:53:05 +00:00
state . stack_size = 0 ;
}
}
2017-11-16 17:38:18 +00:00
void GDScriptFunctionState : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " resume " , " arg " ) , & GDScriptFunctionState : : resume , DEFVAL ( Variant ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " is_valid " , " extended_check " ) , & GDScriptFunctionState : : is_valid , DEFVAL ( false ) ) ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " _signal_callback " , & GDScriptFunctionState : : _signal_callback , MethodInfo ( " _signal_callback " ) ) ;
2017-06-23 00:29:23 +00:00
2017-10-05 11:44:00 +00:00
ADD_SIGNAL ( MethodInfo ( " completed " , PropertyInfo ( Variant : : NIL , " result " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NIL_IS_VARIANT ) ) ) ;
2016-06-01 01:28:27 +00:00
}
2020-05-05 10:53:05 +00:00
GDScriptFunctionState : : GDScriptFunctionState ( ) :
scripts_list ( this ) ,
instances_list ( this ) {
2020-04-01 23:20:12 +00:00
function = nullptr ;
2016-06-01 01:28:27 +00:00
}
2017-11-16 17:38:18 +00:00
GDScriptFunctionState : : ~ GDScriptFunctionState ( ) {
2020-05-05 10:53:05 +00:00
_clear_stack ( ) ;
{
MutexLock lock ( GDScriptLanguage : : singleton - > lock ) ;
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2016-06-01 01:28:27 +00:00
}
}