gdscript_function.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**************************************************************************/
  2. /* gdscript_function.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "gdscript_function.h"
  31. #include "gdscript.h"
  32. Variant GDScriptFunction::get_constant(int p_idx) const {
  33. ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>");
  34. return constants[p_idx];
  35. }
  36. StringName GDScriptFunction::get_global_name(int p_idx) const {
  37. ERR_FAIL_INDEX_V(p_idx, global_names.size(), "<errgname>");
  38. return global_names[p_idx];
  39. }
  40. struct _GDFKC {
  41. int order = 0;
  42. List<int> pos;
  43. };
  44. struct _GDFKCS {
  45. int order = 0;
  46. StringName id;
  47. int pos = 0;
  48. bool operator<(const _GDFKCS &p_r) const {
  49. return order < p_r.order;
  50. }
  51. };
  52. void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const {
  53. int oc = 0;
  54. HashMap<StringName, _GDFKC> sdmap;
  55. for (const StackDebug &sd : stack_debug) {
  56. if (sd.line >= p_line) {
  57. break;
  58. }
  59. if (sd.added) {
  60. if (!sdmap.has(sd.identifier)) {
  61. _GDFKC d;
  62. d.order = oc++;
  63. d.pos.push_back(sd.pos);
  64. sdmap[sd.identifier] = d;
  65. } else {
  66. sdmap[sd.identifier].pos.push_back(sd.pos);
  67. }
  68. } else {
  69. ERR_CONTINUE(!sdmap.has(sd.identifier));
  70. sdmap[sd.identifier].pos.pop_back();
  71. if (sdmap[sd.identifier].pos.is_empty()) {
  72. sdmap.erase(sd.identifier);
  73. }
  74. }
  75. }
  76. List<_GDFKCS> stackpositions;
  77. for (const KeyValue<StringName, _GDFKC> &E : sdmap) {
  78. _GDFKCS spp;
  79. spp.id = E.key;
  80. spp.order = E.value.order;
  81. spp.pos = E.value.pos.back()->get();
  82. stackpositions.push_back(spp);
  83. }
  84. stackpositions.sort();
  85. for (_GDFKCS &E : stackpositions) {
  86. Pair<StringName, int> p;
  87. p.first = E.id;
  88. p.second = E.pos;
  89. r_stackvars->push_back(p);
  90. }
  91. }
  92. GDScriptFunction::GDScriptFunction() {
  93. name = "<anonymous>";
  94. #ifdef DEBUG_ENABLED
  95. {
  96. MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
  97. GDScriptLanguage::get_singleton()->function_list.add(&function_list);
  98. }
  99. #endif
  100. }
  101. GDScriptFunction::~GDScriptFunction() {
  102. get_script()->member_functions.erase(name);
  103. for (int i = 0; i < lambdas.size(); i++) {
  104. memdelete(lambdas[i]);
  105. }
  106. for (int i = 0; i < argument_types.size(); i++) {
  107. argument_types.write[i].script_type_ref = Ref<Script>();
  108. }
  109. return_type.script_type_ref = Ref<Script>();
  110. #ifdef DEBUG_ENABLED
  111. MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
  112. GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
  113. #endif
  114. }
  115. /////////////////////
  116. Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
  117. Variant arg;
  118. r_error.error = Callable::CallError::CALL_OK;
  119. if (p_argcount == 0) {
  120. r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
  121. r_error.expected = 1;
  122. return Variant();
  123. } else if (p_argcount == 1) {
  124. //noooneee
  125. } else if (p_argcount == 2) {
  126. arg = *p_args[0];
  127. } else {
  128. Array extra_args;
  129. for (int i = 0; i < p_argcount - 1; i++) {
  130. extra_args.push_back(*p_args[i]);
  131. }
  132. arg = extra_args;
  133. }
  134. Ref<GDScriptFunctionState> self = *p_args[p_argcount - 1];
  135. if (self.is_null()) {
  136. r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
  137. r_error.argument = p_argcount - 1;
  138. r_error.expected = Variant::OBJECT;
  139. return Variant();
  140. }
  141. return resume(arg);
  142. }
  143. bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
  144. if (function == nullptr) {
  145. return false;
  146. }
  147. if (p_extended_check) {
  148. MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
  149. // Script gone?
  150. if (!scripts_list.in_list()) {
  151. return false;
  152. }
  153. // Class instance gone? (if not static function)
  154. if (state.instance && !instances_list.in_list()) {
  155. return false;
  156. }
  157. }
  158. return true;
  159. }
  160. Variant GDScriptFunctionState::resume(const Variant &p_arg) {
  161. ERR_FAIL_NULL_V(function, Variant());
  162. {
  163. MutexLock lock(GDScriptLanguage::singleton->mutex);
  164. if (!scripts_list.in_list()) {
  165. #ifdef DEBUG_ENABLED
  166. ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after await, but script is gone. At script: " + state.script_path + ":" + itos(state.line));
  167. #else
  168. return Variant();
  169. #endif
  170. }
  171. if (state.instance && !instances_list.in_list()) {
  172. #ifdef DEBUG_ENABLED
  173. 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));
  174. #else
  175. return Variant();
  176. #endif
  177. }
  178. // Do these now to avoid locking again after the call
  179. scripts_list.remove_from_list();
  180. instances_list.remove_from_list();
  181. }
  182. state.result = p_arg;
  183. Callable::CallError err;
  184. Variant ret = function->call(nullptr, nullptr, 0, err, &state);
  185. bool completed = true;
  186. // If the return value is a GDScriptFunctionState reference,
  187. // then the function did await again after resuming.
  188. if (ret.is_ref_counted()) {
  189. GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);
  190. if (gdfs && gdfs->function == function) {
  191. completed = false;
  192. gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this);
  193. }
  194. }
  195. function = nullptr; //cleaned up;
  196. state.result = Variant();
  197. if (completed) {
  198. if (first_state.is_valid()) {
  199. first_state->emit_signal(SNAME("completed"), ret);
  200. } else {
  201. emit_signal(SNAME("completed"), ret);
  202. }
  203. #ifdef DEBUG_ENABLED
  204. if (EngineDebugger::is_active()) {
  205. GDScriptLanguage::get_singleton()->exit_function();
  206. }
  207. _clear_stack();
  208. #endif
  209. }
  210. return ret;
  211. }
  212. void GDScriptFunctionState::_clear_stack() {
  213. if (state.stack_size) {
  214. Variant *stack = (Variant *)state.stack.ptr();
  215. // The first 3 are special addresses and not copied to the state, so we skip them here.
  216. for (int i = 3; i < state.stack_size; i++) {
  217. stack[i].~Variant();
  218. }
  219. state.stack_size = 0;
  220. }
  221. }
  222. void GDScriptFunctionState::_clear_connections() {
  223. List<Object::Connection> conns;
  224. get_signals_connected_to_this(&conns);
  225. for (Object::Connection &c : conns) {
  226. c.signal.disconnect(c.callable);
  227. }
  228. }
  229. void GDScriptFunctionState::_bind_methods() {
  230. ClassDB::bind_method(D_METHOD("resume", "arg"), &GDScriptFunctionState::resume, DEFVAL(Variant()));
  231. ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDScriptFunctionState::is_valid, DEFVAL(false));
  232. ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDScriptFunctionState::_signal_callback, MethodInfo("_signal_callback"));
  233. ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
  234. }
  235. GDScriptFunctionState::GDScriptFunctionState() :
  236. scripts_list(this),
  237. instances_list(this) {
  238. }
  239. GDScriptFunctionState::~GDScriptFunctionState() {
  240. {
  241. MutexLock lock(GDScriptLanguage::singleton->mutex);
  242. scripts_list.remove_from_list();
  243. instances_list.remove_from_list();
  244. }
  245. }