gdscript_function.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*************************************************************************/
  2. /* gdscript_function.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  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. const int *GDScriptFunction::get_code() const {
  33. return _code_ptr;
  34. }
  35. int GDScriptFunction::get_code_size() const {
  36. return _code_size;
  37. }
  38. Variant GDScriptFunction::get_constant(int p_idx) const {
  39. ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>");
  40. return constants[p_idx];
  41. }
  42. StringName GDScriptFunction::get_global_name(int p_idx) const {
  43. ERR_FAIL_INDEX_V(p_idx, global_names.size(), "<errgname>");
  44. return global_names[p_idx];
  45. }
  46. int GDScriptFunction::get_default_argument_count() const {
  47. return _default_arg_count;
  48. }
  49. int GDScriptFunction::get_default_argument_addr(int p_idx) const {
  50. ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), -1);
  51. return default_arguments[p_idx];
  52. }
  53. GDScriptDataType GDScriptFunction::get_return_type() const {
  54. return return_type;
  55. }
  56. GDScriptDataType GDScriptFunction::get_argument_type(int p_idx) const {
  57. ERR_FAIL_INDEX_V(p_idx, argument_types.size(), GDScriptDataType());
  58. return argument_types[p_idx];
  59. }
  60. StringName GDScriptFunction::get_name() const {
  61. return name;
  62. }
  63. int GDScriptFunction::get_max_stack_size() const {
  64. return _stack_size;
  65. }
  66. struct _GDFKC {
  67. int order = 0;
  68. List<int> pos;
  69. };
  70. struct _GDFKCS {
  71. int order = 0;
  72. StringName id;
  73. int pos = 0;
  74. bool operator<(const _GDFKCS &p_r) const {
  75. return order < p_r.order;
  76. }
  77. };
  78. void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const {
  79. int oc = 0;
  80. Map<StringName, _GDFKC> sdmap;
  81. for (const List<StackDebug>::Element *E = stack_debug.front(); E; E = E->next()) {
  82. const StackDebug &sd = E->get();
  83. if (sd.line > p_line) {
  84. break;
  85. }
  86. if (sd.added) {
  87. if (!sdmap.has(sd.identifier)) {
  88. _GDFKC d;
  89. d.order = oc++;
  90. d.pos.push_back(sd.pos);
  91. sdmap[sd.identifier] = d;
  92. } else {
  93. sdmap[sd.identifier].pos.push_back(sd.pos);
  94. }
  95. } else {
  96. ERR_CONTINUE(!sdmap.has(sd.identifier));
  97. sdmap[sd.identifier].pos.pop_back();
  98. if (sdmap[sd.identifier].pos.is_empty()) {
  99. sdmap.erase(sd.identifier);
  100. }
  101. }
  102. }
  103. List<_GDFKCS> stackpositions;
  104. for (Map<StringName, _GDFKC>::Element *E = sdmap.front(); E; E = E->next()) {
  105. _GDFKCS spp;
  106. spp.id = E->key();
  107. spp.order = E->get().order;
  108. spp.pos = E->get().pos.back()->get();
  109. stackpositions.push_back(spp);
  110. }
  111. stackpositions.sort();
  112. for (List<_GDFKCS>::Element *E = stackpositions.front(); E; E = E->next()) {
  113. Pair<StringName, int> p;
  114. p.first = E->get().id;
  115. p.second = E->get().pos;
  116. r_stackvars->push_back(p);
  117. }
  118. }
  119. GDScriptFunction::GDScriptFunction() {
  120. name = "<anonymous>";
  121. #ifdef DEBUG_ENABLED
  122. {
  123. MutexLock lock(GDScriptLanguage::get_singleton()->lock);
  124. GDScriptLanguage::get_singleton()->function_list.add(&function_list);
  125. }
  126. #endif
  127. }
  128. GDScriptFunction::~GDScriptFunction() {
  129. #ifdef DEBUG_ENABLED
  130. MutexLock lock(GDScriptLanguage::get_singleton()->lock);
  131. GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
  132. #endif
  133. }
  134. /////////////////////
  135. Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
  136. Variant arg;
  137. r_error.error = Callable::CallError::CALL_OK;
  138. if (p_argcount == 0) {
  139. r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
  140. r_error.argument = 1;
  141. return Variant();
  142. } else if (p_argcount == 1) {
  143. //noooneee
  144. } else if (p_argcount == 2) {
  145. arg = *p_args[0];
  146. } else {
  147. Array extra_args;
  148. for (int i = 0; i < p_argcount - 1; i++) {
  149. extra_args.push_back(*p_args[i]);
  150. }
  151. arg = extra_args;
  152. }
  153. Ref<GDScriptFunctionState> self = *p_args[p_argcount - 1];
  154. if (self.is_null()) {
  155. r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
  156. r_error.argument = p_argcount - 1;
  157. r_error.expected = Variant::OBJECT;
  158. return Variant();
  159. }
  160. return resume(arg);
  161. }
  162. bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
  163. if (function == nullptr) {
  164. return false;
  165. }
  166. if (p_extended_check) {
  167. MutexLock lock(GDScriptLanguage::get_singleton()->lock);
  168. // Script gone?
  169. if (!scripts_list.in_list()) {
  170. return false;
  171. }
  172. // Class instance gone? (if not static function)
  173. if (state.instance && !instances_list.in_list()) {
  174. return false;
  175. }
  176. }
  177. return true;
  178. }
  179. Variant GDScriptFunctionState::resume(const Variant &p_arg) {
  180. ERR_FAIL_COND_V(!function, Variant());
  181. {
  182. MutexLock lock(GDScriptLanguage::singleton->lock);
  183. if (!scripts_list.in_list()) {
  184. #ifdef DEBUG_ENABLED
  185. ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after await, but script is gone. At script: " + state.script_path + ":" + itos(state.line));
  186. #else
  187. return Variant();
  188. #endif
  189. }
  190. if (state.instance && !instances_list.in_list()) {
  191. #ifdef DEBUG_ENABLED
  192. 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));
  193. #else
  194. return Variant();
  195. #endif
  196. }
  197. // Do these now to avoid locking again after the call
  198. scripts_list.remove_from_list();
  199. instances_list.remove_from_list();
  200. }
  201. state.result = p_arg;
  202. Callable::CallError err;
  203. Variant ret = function->call(nullptr, nullptr, 0, err, &state);
  204. bool completed = true;
  205. // If the return value is a GDScriptFunctionState reference,
  206. // then the function did await again after resuming.
  207. if (ret.is_ref()) {
  208. GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);
  209. if (gdfs && gdfs->function == function) {
  210. completed = false;
  211. gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this);
  212. }
  213. }
  214. function = nullptr; //cleaned up;
  215. state.result = Variant();
  216. if (completed) {
  217. if (first_state.is_valid()) {
  218. first_state->emit_signal("completed", ret);
  219. } else {
  220. emit_signal("completed", ret);
  221. }
  222. #ifdef DEBUG_ENABLED
  223. if (EngineDebugger::is_active()) {
  224. GDScriptLanguage::get_singleton()->exit_function();
  225. }
  226. #endif
  227. }
  228. return ret;
  229. }
  230. void GDScriptFunctionState::_clear_stack() {
  231. if (state.stack_size) {
  232. Variant *stack = (Variant *)state.stack.ptr();
  233. for (int i = 0; i < state.stack_size; i++) {
  234. stack[i].~Variant();
  235. }
  236. state.stack_size = 0;
  237. }
  238. }
  239. void GDScriptFunctionState::_bind_methods() {
  240. ClassDB::bind_method(D_METHOD("resume", "arg"), &GDScriptFunctionState::resume, DEFVAL(Variant()));
  241. ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDScriptFunctionState::is_valid, DEFVAL(false));
  242. ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDScriptFunctionState::_signal_callback, MethodInfo("_signal_callback"));
  243. ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
  244. }
  245. GDScriptFunctionState::GDScriptFunctionState() :
  246. scripts_list(this),
  247. instances_list(this) {
  248. }
  249. GDScriptFunctionState::~GDScriptFunctionState() {
  250. _clear_stack();
  251. {
  252. MutexLock lock(GDScriptLanguage::singleton->lock);
  253. scripts_list.remove_from_list();
  254. instances_list.remove_from_list();
  255. }
  256. }