2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* gdscript_function.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2017-11-16 18:38:18 +01:00
# include "gdscript_function.h"
2017-03-05 15:47:28 +01:00
2017-11-16 18:38:18 +01:00
# include "gdscript.h"
2016-06-01 03:28:27 +02:00
2017-11-16 18:38:18 +01:00
Variant GDScriptFunction : : get_constant ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , constants . size ( ) , " <errconst> " ) ;
2016-06-01 03:28:27 +02:00
return constants [ p_idx ] ;
}
2017-11-16 18:38:18 +01:00
StringName GDScriptFunction : : get_global_name ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , global_names . size ( ) , " <errgname> " ) ;
2016-06-01 03:28:27 +02:00
return global_names [ p_idx ] ;
}
struct _GDFKC {
2021-02-08 10:57:18 +01:00
int order = 0 ;
2016-06-01 03:28:27 +02:00
List < int > pos ;
} ;
struct _GDFKCS {
2021-02-08 10:57:18 +01:00
int order = 0 ;
2016-06-01 03:28:27 +02:00
StringName id ;
2021-02-08 10:57:18 +01:00
int pos = 0 ;
2016-06-01 03:28:27 +02:00
bool operator < ( const _GDFKCS & p_r ) const {
2017-03-05 16:44:50 +01:00
return order < p_r . order ;
2016-06-01 03:28:27 +02:00
}
} ;
2020-03-17 07:33:00 +01:00
void GDScriptFunction : : debug_get_stack_member_state ( int p_line , List < Pair < StringName , int > > * r_stackvars ) const {
2017-03-05 16:44:50 +01:00
int oc = 0 ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , _GDFKC > sdmap ;
2021-07-16 05:45:57 +02:00
for ( const StackDebug & sd : stack_debug ) {
2022-02-16 19:12:38 +01:00
if ( sd . line > = p_line ) {
2016-06-01 03:28:27 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-06-01 03:28:27 +02:00
if ( sd . added ) {
if ( ! sdmap . has ( sd . identifier ) ) {
_GDFKC d ;
2017-03-05 16:44:50 +01:00
d . order = oc + + ;
2016-06-01 03:28:27 +02:00
d . pos . push_back ( sd . pos ) ;
2017-03-05 16:44:50 +01:00
sdmap [ sd . identifier ] = d ;
2016-06-01 03:28:27 +02:00
} else {
sdmap [ sd . identifier ] . pos . push_back ( sd . pos ) ;
}
} else {
ERR_CONTINUE ( ! sdmap . has ( sd . identifier ) ) ;
sdmap [ sd . identifier ] . pos . pop_back ( ) ;
2020-12-15 13:04:21 +01:00
if ( sdmap [ sd . identifier ] . pos . is_empty ( ) ) {
2016-06-01 03:28:27 +02:00
sdmap . erase ( sd . identifier ) ;
2020-05-14 16:41:43 +02:00
}
2016-06-01 03:28:27 +02:00
}
}
List < _GDFKCS > stackpositions ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , _GDFKC > & E : sdmap ) {
2016-06-01 03:28:27 +02:00
_GDFKCS spp ;
2021-08-09 22:13:42 +02:00
spp . id = E . key ;
spp . order = E . value . order ;
spp . pos = E . value . pos . back ( ) - > get ( ) ;
2016-06-01 03:28:27 +02:00
stackpositions . push_back ( spp ) ;
}
stackpositions . sort ( ) ;
2021-07-16 05:45:57 +02:00
for ( _GDFKCS & E : stackpositions ) {
2017-03-05 16:44:50 +01:00
Pair < StringName , int > p ;
2021-07-16 05:45:57 +02:00
p . first = E . id ;
p . second = E . pos ;
2016-06-01 03:28:27 +02:00
r_stackvars - > push_back ( p ) ;
}
}
2020-11-13 14:31:14 +01:00
GDScriptFunction : : GDScriptFunction ( ) {
2017-03-05 16:44:50 +01:00
name = " <anonymous> " ;
2016-06-01 03:28:27 +02:00
# ifdef DEBUG_ENABLED
2020-02-26 11:28:13 +01:00
{
2022-09-29 11:53:28 +02:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > mutex ) ;
2020-02-26 11:28:13 +01:00
GDScriptLanguage : : get_singleton ( ) - > function_list . add ( & function_list ) ;
2016-06-01 03:28:27 +02:00
}
# endif
}
2017-11-16 18:38:18 +01:00
GDScriptFunction : : ~ GDScriptFunction ( ) {
2022-10-09 18:41:28 +02:00
get_script ( ) - > member_functions . erase ( name ) ;
2021-03-28 16:03:13 +02:00
for ( int i = 0 ; i < lambdas . size ( ) ; i + + ) {
memdelete ( lambdas [ i ] ) ;
}
2022-10-09 18:41:28 +02:00
for ( int i = 0 ; i < argument_types . size ( ) ; i + + ) {
argument_types . write [ i ] . script_type_ref = Ref < Script > ( ) ;
}
return_type . script_type_ref = Ref < Script > ( ) ;
2016-06-01 03:28:27 +02:00
# ifdef DEBUG_ENABLED
2022-09-29 11:53:28 +02:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > mutex ) ;
2020-02-26 11:28:13 +01:00
GDScriptLanguage : : get_singleton ( ) - > function_list . remove ( & function_list ) ;
2016-06-01 03:28:27 +02:00
# endif
}
/////////////////////
2020-02-19 20:27:19 +01:00
Variant GDScriptFunctionState : : _signal_callback ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2016-06-01 03:28:27 +02:00
Variant arg ;
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-06-01 03:28:27 +02:00
2017-03-05 16:44:50 +01:00
if ( p_argcount = = 0 ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2023-09-29 18:19:46 +02:00
r_error . expected = 1 ;
2016-06-01 03:28:27 +02:00
return Variant ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( p_argcount = = 1 ) {
2016-06-01 03:28:27 +02:00
//noooneee
2017-03-05 16:44:50 +01:00
} else if ( p_argcount = = 2 ) {
arg = * p_args [ 0 ] ;
2016-06-01 03:28:27 +02:00
} else {
Array extra_args ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_argcount - 1 ; i + + ) {
2016-06-01 03:28:27 +02:00
extra_args . push_back ( * p_args [ i ] ) ;
}
2017-03-05 16:44:50 +01:00
arg = extra_args ;
2016-06-01 03:28:27 +02:00
}
2017-11-16 18:38:18 +01:00
Ref < GDScriptFunctionState > self = * p_args [ p_argcount - 1 ] ;
2016-06-01 03:28:27 +02:00
if ( self . is_null ( ) ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 16:44:50 +01:00
r_error . argument = p_argcount - 1 ;
r_error . expected = Variant : : OBJECT ;
2016-06-01 03:28:27 +02:00
return Variant ( ) ;
}
2019-07-17 22:47:00 +02:00
return resume ( arg ) ;
2016-06-01 03:28:27 +02:00
}
2017-11-16 18:38:18 +01:00
bool GDScriptFunctionState : : is_valid ( bool p_extended_check ) const {
2020-05-14 16:41:43 +02:00
if ( function = = nullptr ) {
2017-05-17 14:47:17 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-05-17 14:47:17 +02:00
if ( p_extended_check ) {
2022-09-29 11:53:28 +02:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > mutex ) ;
2020-05-05 12:53:05 +02:00
// Script gone?
if ( ! scripts_list . in_list ( ) ) {
2017-05-17 14:47:17 +02:00
return false ;
2020-04-29 13:38:00 +02:00
}
2020-05-05 12:53:05 +02:00
// Class instance gone? (if not static function)
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 13:38:00 +02:00
return false ;
}
2017-05-17 14:47:17 +02:00
}
2016-06-01 03:28:27 +02:00
2017-05-17 14:47:17 +02:00
return true ;
2016-06-01 03:28:27 +02:00
}
2017-11-16 18:38:18 +01:00
Variant GDScriptFunctionState : : resume ( const Variant & p_arg ) {
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( function , Variant ( ) ) ;
2020-05-05 12:53:05 +02:00
{
2022-09-29 11:53:28 +02:00
MutexLock lock ( GDScriptLanguage : : singleton - > mutex ) ;
2020-05-05 12:53:05 +02:00
if ( ! scripts_list . in_list ( ) ) {
2018-11-25 12:38:12 +01:00
# ifdef DEBUG_ENABLED
2020-05-02 00:14:56 +02: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 13:38:00 +02:00
# else
2020-05-05 12:53:05 +02:00
return Variant ( ) ;
2020-04-29 13:38:00 +02:00
# endif
2020-05-05 12:53:05 +02:00
}
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 13:38:00 +02:00
# ifdef DEBUG_ENABLED
2020-05-02 00:14:56 +02: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 12:38:12 +01:00
# else
2020-05-05 12:53:05 +02:00
return Variant ( ) ;
2016-06-30 02:06:16 +02:00
# endif
2020-05-05 12:53:05 +02:00
}
// Do these now to avoid locking again after the call
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2018-11-25 12:38:12 +01:00
}
2016-06-01 03:28:27 +02:00
2017-03-05 16:44:50 +01:00
state . result = p_arg ;
2020-02-19 20:27:19 +01:00
Callable : : CallError err ;
2020-04-02 01:20:12 +02:00
Variant ret = function - > call ( nullptr , nullptr , 0 , err , & state ) ;
2017-06-23 02:29:23 +02:00
bool completed = true ;
2017-11-16 18:38:18 +01:00
// If the return value is a GDScriptFunctionState reference,
2021-03-12 14:35:16 +01:00
// then the function did await again after resuming.
2021-08-26 21:37:17 +02:00
if ( ret . is_ref_counted ( ) ) {
2017-11-16 18:38:18 +01:00
GDScriptFunctionState * gdfs = Object : : cast_to < GDScriptFunctionState > ( ret ) ;
2018-03-14 16:42:13 +01:00
if ( gdfs & & gdfs - > function = = function ) {
2017-06-23 02:29:23 +02:00
completed = false ;
2018-06-28 17:40:11 +02:00
gdfs - > first_state = first_state . is_valid ( ) ? first_state : Ref < GDScriptFunctionState > ( this ) ;
2018-03-14 16:42:13 +01:00
}
2017-06-23 02:29:23 +02:00
}
2020-04-02 01:20:12 +02:00
function = nullptr ; //cleaned up;
2017-03-05 16:44:50 +01:00
state . result = Variant ( ) ;
2017-06-23 02:29:23 +02:00
if ( completed ) {
2018-06-28 17:40:11 +02:00
if ( first_state . is_valid ( ) ) {
2021-07-17 23:22:52 +02:00
first_state - > emit_signal ( SNAME ( " completed " ) , ret ) ;
2018-06-28 17:40:11 +02:00
} else {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " completed " ) , ret ) ;
2018-03-14 16:42:13 +01:00
}
2019-05-10 21:38:48 +02:00
# ifdef DEBUG_ENABLED
2020-05-14 16:41:43 +02:00
if ( EngineDebugger : : is_active ( ) ) {
2019-05-10 21:38:48 +02:00
GDScriptLanguage : : get_singleton ( ) - > exit_function ( ) ;
2020-05-14 16:41:43 +02:00
}
2022-05-27 14:13:25 +02:00
_clear_stack ( ) ;
2019-05-10 21:38:48 +02:00
# endif
2017-06-23 02:29:23 +02:00
}
2016-06-01 03:28:27 +02:00
return ret ;
}
2020-05-05 12:53:05 +02:00
void GDScriptFunctionState : : _clear_stack ( ) {
if ( state . stack_size ) {
Variant * stack = ( Variant * ) state . stack . ptr ( ) ;
2022-05-13 19:03:48 +02:00
// The first 3 are special addresses and not copied to the state, so we skip them here.
for ( int i = 3 ; i < state . stack_size ; i + + ) {
2020-05-05 12:53:05 +02:00
stack [ i ] . ~ Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-05-05 12:53:05 +02:00
state . stack_size = 0 ;
}
}
2022-09-16 17:42:06 +02:00
void GDScriptFunctionState : : _clear_connections ( ) {
List < Object : : Connection > conns ;
get_signals_connected_to_this ( & conns ) ;
for ( Object : : Connection & c : conns ) {
c . signal . disconnect ( c . callable ) ;
}
}
2017-11-16 18:38:18 +01: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 02:29:23 +02:00
2017-10-05 13:44:00 +02:00
ADD_SIGNAL ( MethodInfo ( " completed " , PropertyInfo ( Variant : : NIL , " result " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NIL_IS_VARIANT ) ) ) ;
2016-06-01 03:28:27 +02:00
}
2020-05-05 12:53:05 +02:00
GDScriptFunctionState : : GDScriptFunctionState ( ) :
scripts_list ( this ) ,
instances_list ( this ) {
2016-06-01 03:28:27 +02:00
}
2017-11-16 18:38:18 +01:00
GDScriptFunctionState : : ~ GDScriptFunctionState ( ) {
2020-05-05 12:53:05 +02:00
{
2022-09-29 11:53:28 +02:00
MutexLock lock ( GDScriptLanguage : : singleton - > mutex ) ;
2020-05-05 12:53:05 +02:00
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2016-06-01 03:28:27 +02:00
}
}