test_gdscript.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. /*************************************************************************/
  2. /* test_gdscript.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 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 "test_gdscript.h"
  31. #include "core/os/file_access.h"
  32. #include "core/os/main_loop.h"
  33. #include "core/os/os.h"
  34. #include "modules/modules_enabled.gen.h"
  35. #ifdef MODULE_GDSCRIPT_ENABLED
  36. #include "modules/gdscript/gdscript.h"
  37. #include "modules/gdscript/gdscript_compiler.h"
  38. #include "modules/gdscript/gdscript_parser.h"
  39. #include "modules/gdscript/gdscript_tokenizer.h"
  40. namespace TestGDScript {
  41. static void _print_indent(int p_ident, const String &p_text) {
  42. String txt;
  43. for (int i = 0; i < p_ident; i++) {
  44. txt += '\t';
  45. }
  46. print_line(txt + p_text);
  47. }
  48. static String _parser_extends(const GDScriptParser::ClassNode *p_class) {
  49. String txt = "extends ";
  50. if (String(p_class->extends_file) != "") {
  51. txt += "\"" + p_class->extends_file + "\"";
  52. if (p_class->extends_class.size())
  53. txt += ".";
  54. }
  55. for (int i = 0; i < p_class->extends_class.size(); i++) {
  56. if (i != 0)
  57. txt += ".";
  58. txt += p_class->extends_class[i];
  59. }
  60. return txt;
  61. }
  62. static String _parser_expr(const GDScriptParser::Node *p_expr) {
  63. String txt;
  64. switch (p_expr->type) {
  65. case GDScriptParser::Node::TYPE_IDENTIFIER: {
  66. const GDScriptParser::IdentifierNode *id_node = static_cast<const GDScriptParser::IdentifierNode *>(p_expr);
  67. txt = id_node->name;
  68. } break;
  69. case GDScriptParser::Node::TYPE_CONSTANT: {
  70. const GDScriptParser::ConstantNode *c_node = static_cast<const GDScriptParser::ConstantNode *>(p_expr);
  71. if (c_node->value.get_type() == Variant::STRING)
  72. txt = "\"" + String(c_node->value) + "\"";
  73. else
  74. txt = c_node->value;
  75. } break;
  76. case GDScriptParser::Node::TYPE_SELF: {
  77. txt = "self";
  78. } break;
  79. case GDScriptParser::Node::TYPE_ARRAY: {
  80. const GDScriptParser::ArrayNode *arr_node = static_cast<const GDScriptParser::ArrayNode *>(p_expr);
  81. txt += "[";
  82. for (int i = 0; i < arr_node->elements.size(); i++) {
  83. if (i > 0)
  84. txt += ", ";
  85. txt += _parser_expr(arr_node->elements[i]);
  86. }
  87. txt += "]";
  88. } break;
  89. case GDScriptParser::Node::TYPE_DICTIONARY: {
  90. const GDScriptParser::DictionaryNode *dict_node = static_cast<const GDScriptParser::DictionaryNode *>(p_expr);
  91. txt += "{";
  92. for (int i = 0; i < dict_node->elements.size(); i++) {
  93. if (i > 0)
  94. txt += ", ";
  95. const GDScriptParser::DictionaryNode::Pair &p = dict_node->elements[i];
  96. txt += _parser_expr(p.key);
  97. txt += ":";
  98. txt += _parser_expr(p.value);
  99. }
  100. txt += "}";
  101. } break;
  102. case GDScriptParser::Node::TYPE_OPERATOR: {
  103. const GDScriptParser::OperatorNode *c_node = static_cast<const GDScriptParser::OperatorNode *>(p_expr);
  104. switch (c_node->op) {
  105. case GDScriptParser::OperatorNode::OP_PARENT_CALL:
  106. txt += ".";
  107. [[fallthrough]];
  108. case GDScriptParser::OperatorNode::OP_CALL: {
  109. ERR_FAIL_COND_V(c_node->arguments.size() < 1, "");
  110. String func_name;
  111. const GDScriptParser::Node *nfunc = c_node->arguments[0];
  112. int arg_ofs = 0;
  113. if (nfunc->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) {
  114. const GDScriptParser::BuiltInFunctionNode *bif_node = static_cast<const GDScriptParser::BuiltInFunctionNode *>(nfunc);
  115. func_name = GDScriptFunctions::get_func_name(bif_node->function);
  116. arg_ofs = 1;
  117. } else if (nfunc->type == GDScriptParser::Node::TYPE_TYPE) {
  118. const GDScriptParser::TypeNode *t_node = static_cast<const GDScriptParser::TypeNode *>(nfunc);
  119. func_name = Variant::get_type_name(t_node->vtype);
  120. arg_ofs = 1;
  121. } else {
  122. ERR_FAIL_COND_V(c_node->arguments.size() < 2, "");
  123. nfunc = c_node->arguments[1];
  124. ERR_FAIL_COND_V(nfunc->type != GDScriptParser::Node::TYPE_IDENTIFIER, "");
  125. if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF)
  126. func_name = _parser_expr(c_node->arguments[0]) + ".";
  127. func_name += _parser_expr(nfunc);
  128. arg_ofs = 2;
  129. }
  130. txt += func_name + "(";
  131. for (int i = arg_ofs; i < c_node->arguments.size(); i++) {
  132. const GDScriptParser::Node *arg = c_node->arguments[i];
  133. if (i > arg_ofs)
  134. txt += ", ";
  135. txt += _parser_expr(arg);
  136. }
  137. txt += ")";
  138. } break;
  139. case GDScriptParser::OperatorNode::OP_INDEX: {
  140. ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
  141. //index with []
  142. txt = _parser_expr(c_node->arguments[0]) + "[" + _parser_expr(c_node->arguments[1]) + "]";
  143. } break;
  144. case GDScriptParser::OperatorNode::OP_INDEX_NAMED: {
  145. ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
  146. txt = _parser_expr(c_node->arguments[0]) + "." + _parser_expr(c_node->arguments[1]);
  147. } break;
  148. case GDScriptParser::OperatorNode::OP_NEG: {
  149. txt = "-" + _parser_expr(c_node->arguments[0]);
  150. } break;
  151. case GDScriptParser::OperatorNode::OP_NOT: {
  152. txt = "not " + _parser_expr(c_node->arguments[0]);
  153. } break;
  154. case GDScriptParser::OperatorNode::OP_BIT_INVERT: {
  155. txt = "~" + _parser_expr(c_node->arguments[0]);
  156. } break;
  157. case GDScriptParser::OperatorNode::OP_IN: {
  158. txt = _parser_expr(c_node->arguments[0]) + " in " + _parser_expr(c_node->arguments[1]);
  159. } break;
  160. case GDScriptParser::OperatorNode::OP_EQUAL: {
  161. txt = _parser_expr(c_node->arguments[0]) + "==" + _parser_expr(c_node->arguments[1]);
  162. } break;
  163. case GDScriptParser::OperatorNode::OP_NOT_EQUAL: {
  164. txt = _parser_expr(c_node->arguments[0]) + "!=" + _parser_expr(c_node->arguments[1]);
  165. } break;
  166. case GDScriptParser::OperatorNode::OP_LESS: {
  167. txt = _parser_expr(c_node->arguments[0]) + "<" + _parser_expr(c_node->arguments[1]);
  168. } break;
  169. case GDScriptParser::OperatorNode::OP_LESS_EQUAL: {
  170. txt = _parser_expr(c_node->arguments[0]) + "<=" + _parser_expr(c_node->arguments[1]);
  171. } break;
  172. case GDScriptParser::OperatorNode::OP_GREATER: {
  173. txt = _parser_expr(c_node->arguments[0]) + ">" + _parser_expr(c_node->arguments[1]);
  174. } break;
  175. case GDScriptParser::OperatorNode::OP_GREATER_EQUAL: {
  176. txt = _parser_expr(c_node->arguments[0]) + ">=" + _parser_expr(c_node->arguments[1]);
  177. } break;
  178. case GDScriptParser::OperatorNode::OP_AND: {
  179. txt = _parser_expr(c_node->arguments[0]) + " and " + _parser_expr(c_node->arguments[1]);
  180. } break;
  181. case GDScriptParser::OperatorNode::OP_OR: {
  182. txt = _parser_expr(c_node->arguments[0]) + " or " + _parser_expr(c_node->arguments[1]);
  183. } break;
  184. case GDScriptParser::OperatorNode::OP_ADD: {
  185. txt = _parser_expr(c_node->arguments[0]) + "+" + _parser_expr(c_node->arguments[1]);
  186. } break;
  187. case GDScriptParser::OperatorNode::OP_SUB: {
  188. txt = _parser_expr(c_node->arguments[0]) + "-" + _parser_expr(c_node->arguments[1]);
  189. } break;
  190. case GDScriptParser::OperatorNode::OP_MUL: {
  191. txt = _parser_expr(c_node->arguments[0]) + "*" + _parser_expr(c_node->arguments[1]);
  192. } break;
  193. case GDScriptParser::OperatorNode::OP_DIV: {
  194. txt = _parser_expr(c_node->arguments[0]) + "/" + _parser_expr(c_node->arguments[1]);
  195. } break;
  196. case GDScriptParser::OperatorNode::OP_MOD: {
  197. txt = _parser_expr(c_node->arguments[0]) + "%" + _parser_expr(c_node->arguments[1]);
  198. } break;
  199. case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: {
  200. txt = _parser_expr(c_node->arguments[0]) + "<<" + _parser_expr(c_node->arguments[1]);
  201. } break;
  202. case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: {
  203. txt = _parser_expr(c_node->arguments[0]) + ">>" + _parser_expr(c_node->arguments[1]);
  204. } break;
  205. case GDScriptParser::OperatorNode::OP_ASSIGN: {
  206. txt = _parser_expr(c_node->arguments[0]) + "=" + _parser_expr(c_node->arguments[1]);
  207. } break;
  208. case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: {
  209. txt = _parser_expr(c_node->arguments[0]) + "+=" + _parser_expr(c_node->arguments[1]);
  210. } break;
  211. case GDScriptParser::OperatorNode::OP_ASSIGN_SUB: {
  212. txt = _parser_expr(c_node->arguments[0]) + "-=" + _parser_expr(c_node->arguments[1]);
  213. } break;
  214. case GDScriptParser::OperatorNode::OP_ASSIGN_MUL: {
  215. txt = _parser_expr(c_node->arguments[0]) + "*=" + _parser_expr(c_node->arguments[1]);
  216. } break;
  217. case GDScriptParser::OperatorNode::OP_ASSIGN_DIV: {
  218. txt = _parser_expr(c_node->arguments[0]) + "/=" + _parser_expr(c_node->arguments[1]);
  219. } break;
  220. case GDScriptParser::OperatorNode::OP_ASSIGN_MOD: {
  221. txt = _parser_expr(c_node->arguments[0]) + "%=" + _parser_expr(c_node->arguments[1]);
  222. } break;
  223. case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: {
  224. txt = _parser_expr(c_node->arguments[0]) + "<<=" + _parser_expr(c_node->arguments[1]);
  225. } break;
  226. case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: {
  227. txt = _parser_expr(c_node->arguments[0]) + ">>=" + _parser_expr(c_node->arguments[1]);
  228. } break;
  229. case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_AND: {
  230. txt = _parser_expr(c_node->arguments[0]) + "&=" + _parser_expr(c_node->arguments[1]);
  231. } break;
  232. case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_OR: {
  233. txt = _parser_expr(c_node->arguments[0]) + "|=" + _parser_expr(c_node->arguments[1]);
  234. } break;
  235. case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: {
  236. txt = _parser_expr(c_node->arguments[0]) + "^=" + _parser_expr(c_node->arguments[1]);
  237. } break;
  238. case GDScriptParser::OperatorNode::OP_BIT_AND: {
  239. txt = _parser_expr(c_node->arguments[0]) + "&" + _parser_expr(c_node->arguments[1]);
  240. } break;
  241. case GDScriptParser::OperatorNode::OP_BIT_OR: {
  242. txt = _parser_expr(c_node->arguments[0]) + "|" + _parser_expr(c_node->arguments[1]);
  243. } break;
  244. case GDScriptParser::OperatorNode::OP_BIT_XOR: {
  245. txt = _parser_expr(c_node->arguments[0]) + "^" + _parser_expr(c_node->arguments[1]);
  246. } break;
  247. default: {
  248. }
  249. }
  250. } break;
  251. case GDScriptParser::Node::TYPE_CAST: {
  252. const GDScriptParser::CastNode *cast_node = static_cast<const GDScriptParser::CastNode *>(p_expr);
  253. txt = _parser_expr(cast_node->source_node) + " as " + cast_node->cast_type.to_string();
  254. } break;
  255. case GDScriptParser::Node::TYPE_NEWLINE: {
  256. //skippie
  257. } break;
  258. default: {
  259. ERR_FAIL_V_MSG("", "Parser bug at " + itos(p_expr->line) + ", invalid expression type: " + itos(p_expr->type));
  260. }
  261. }
  262. return txt;
  263. }
  264. static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_indent) {
  265. for (int i = 0; i < p_block->statements.size(); i++) {
  266. const GDScriptParser::Node *statement = p_block->statements[i];
  267. switch (statement->type) {
  268. case GDScriptParser::Node::TYPE_CONTROL_FLOW: {
  269. const GDScriptParser::ControlFlowNode *cf_node = static_cast<const GDScriptParser::ControlFlowNode *>(statement);
  270. switch (cf_node->cf_type) {
  271. case GDScriptParser::ControlFlowNode::CF_IF: {
  272. ERR_FAIL_COND(cf_node->arguments.size() != 1);
  273. String txt;
  274. txt += "if ";
  275. txt += _parser_expr(cf_node->arguments[0]);
  276. txt += ":";
  277. _print_indent(p_indent, txt);
  278. ERR_FAIL_COND(!cf_node->body);
  279. _parser_show_block(cf_node->body, p_indent + 1);
  280. if (cf_node->body_else) {
  281. _print_indent(p_indent, "else:");
  282. _parser_show_block(cf_node->body_else, p_indent + 1);
  283. }
  284. } break;
  285. case GDScriptParser::ControlFlowNode::CF_FOR: {
  286. ERR_FAIL_COND(cf_node->arguments.size() != 2);
  287. String txt;
  288. txt += "for ";
  289. txt += _parser_expr(cf_node->arguments[0]);
  290. txt += " in ";
  291. txt += _parser_expr(cf_node->arguments[1]);
  292. txt += ":";
  293. _print_indent(p_indent, txt);
  294. ERR_FAIL_COND(!cf_node->body);
  295. _parser_show_block(cf_node->body, p_indent + 1);
  296. } break;
  297. case GDScriptParser::ControlFlowNode::CF_WHILE: {
  298. ERR_FAIL_COND(cf_node->arguments.size() != 1);
  299. String txt;
  300. txt += "while ";
  301. txt += _parser_expr(cf_node->arguments[0]);
  302. txt += ":";
  303. _print_indent(p_indent, txt);
  304. ERR_FAIL_COND(!cf_node->body);
  305. _parser_show_block(cf_node->body, p_indent + 1);
  306. } break;
  307. case GDScriptParser::ControlFlowNode::CF_MATCH: {
  308. // FIXME: Implement
  309. } break;
  310. case GDScriptParser::ControlFlowNode::CF_CONTINUE: {
  311. _print_indent(p_indent, "continue");
  312. } break;
  313. case GDScriptParser::ControlFlowNode::CF_BREAK: {
  314. _print_indent(p_indent, "break");
  315. } break;
  316. case GDScriptParser::ControlFlowNode::CF_RETURN: {
  317. if (cf_node->arguments.size())
  318. _print_indent(p_indent, "return " + _parser_expr(cf_node->arguments[0]));
  319. else
  320. _print_indent(p_indent, "return ");
  321. } break;
  322. }
  323. } break;
  324. case GDScriptParser::Node::TYPE_LOCAL_VAR: {
  325. const GDScriptParser::LocalVarNode *lv_node = static_cast<const GDScriptParser::LocalVarNode *>(statement);
  326. _print_indent(p_indent, "var " + String(lv_node->name));
  327. } break;
  328. default: {
  329. //expression i guess
  330. _print_indent(p_indent, _parser_expr(statement));
  331. }
  332. }
  333. }
  334. }
  335. static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = nullptr) {
  336. String txt;
  337. if (p_func->_static)
  338. txt = "static ";
  339. txt += "func ";
  340. if (p_func->name == "") // initializer
  341. txt += "[built-in-initializer]";
  342. else
  343. txt += String(p_func->name);
  344. txt += "(";
  345. for (int i = 0; i < p_func->arguments.size(); i++) {
  346. if (i != 0)
  347. txt += ", ";
  348. txt += "var " + String(p_func->arguments[i]);
  349. if (i >= (p_func->arguments.size() - p_func->default_values.size())) {
  350. int defarg = i - (p_func->arguments.size() - p_func->default_values.size());
  351. txt += "=";
  352. txt += _parser_expr(p_func->default_values[defarg]);
  353. }
  354. }
  355. txt += ")";
  356. //todo constructor check!
  357. txt += ":";
  358. _print_indent(p_indent, txt);
  359. if (p_initializer)
  360. _parser_show_block(p_initializer, p_indent + 1);
  361. _parser_show_block(p_func->body, p_indent + 1);
  362. }
  363. static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_indent, const Vector<String> &p_code) {
  364. if (p_indent == 0 && (String(p_class->extends_file) != "" || p_class->extends_class.size())) {
  365. _print_indent(p_indent, _parser_extends(p_class));
  366. print_line("\n");
  367. }
  368. for (int i = 0; i < p_class->subclasses.size(); i++) {
  369. const GDScriptParser::ClassNode *subclass = p_class->subclasses[i];
  370. String line = "class " + subclass->name;
  371. if (String(subclass->extends_file) != "" || subclass->extends_class.size())
  372. line += " " + _parser_extends(subclass);
  373. line += ":";
  374. _print_indent(p_indent, line);
  375. _parser_show_class(subclass, p_indent + 1, p_code);
  376. print_line("\n");
  377. }
  378. for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) {
  379. const GDScriptParser::ClassNode::Constant &constant = E->get();
  380. _print_indent(p_indent, "const " + String(E->key()) + "=" + _parser_expr(constant.expression));
  381. }
  382. for (int i = 0; i < p_class->variables.size(); i++) {
  383. const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
  384. _print_indent(p_indent, "var " + String(m.identifier));
  385. }
  386. print_line("\n");
  387. for (int i = 0; i < p_class->static_functions.size(); i++) {
  388. _parser_show_function(p_class->static_functions[i], p_indent);
  389. print_line("\n");
  390. }
  391. for (int i = 0; i < p_class->functions.size(); i++) {
  392. if (String(p_class->functions[i]->name) == "_init") {
  393. _parser_show_function(p_class->functions[i], p_indent, p_class->initializer);
  394. } else
  395. _parser_show_function(p_class->functions[i], p_indent);
  396. print_line("\n");
  397. }
  398. //_parser_show_function(p_class->initializer,p_indent);
  399. print_line("\n");
  400. }
  401. static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFunction &func, int p_addr) {
  402. int addr = p_addr & GDScriptFunction::ADDR_MASK;
  403. switch (p_addr >> GDScriptFunction::ADDR_BITS) {
  404. case GDScriptFunction::ADDR_TYPE_SELF: {
  405. return "self";
  406. } break;
  407. case GDScriptFunction::ADDR_TYPE_CLASS: {
  408. return "class";
  409. } break;
  410. case GDScriptFunction::ADDR_TYPE_MEMBER: {
  411. return "member(" + p_script->debug_get_member_by_index(addr) + ")";
  412. } break;
  413. case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
  414. return "class_const(" + func.get_global_name(addr) + ")";
  415. } break;
  416. case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
  417. Variant v = func.get_constant(addr);
  418. String txt;
  419. if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH)
  420. txt = "\"" + String(v) + "\"";
  421. else
  422. txt = v;
  423. return "const(" + txt + ")";
  424. } break;
  425. case GDScriptFunction::ADDR_TYPE_STACK: {
  426. return "stack(" + itos(addr) + ")";
  427. } break;
  428. case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
  429. return "var_stack(" + itos(addr) + ")";
  430. } break;
  431. case GDScriptFunction::ADDR_TYPE_GLOBAL: {
  432. return "global(" + func.get_global_name(addr) + ")";
  433. } break;
  434. case GDScriptFunction::ADDR_TYPE_NIL: {
  435. return "nil";
  436. } break;
  437. }
  438. return "<err>";
  439. }
  440. static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String> &p_code) {
  441. const Map<StringName, GDScriptFunction *> &mf = p_class->debug_get_member_functions();
  442. for (const Map<StringName, GDScriptFunction *>::Element *E = mf.front(); E; E = E->next()) {
  443. const GDScriptFunction &func = *E->get();
  444. const int *code = func.get_code();
  445. int codelen = func.get_code_size();
  446. String defargs;
  447. if (func.get_default_argument_count()) {
  448. defargs = "defarg at: ";
  449. for (int i = 0; i < func.get_default_argument_count(); i++) {
  450. if (i > 0)
  451. defargs += ",";
  452. defargs += itos(func.get_default_argument_addr(i));
  453. }
  454. defargs += " ";
  455. }
  456. print_line("== function " + String(func.get_name()) + "() :: stack size: " + itos(func.get_max_stack_size()) + " " + defargs + "==");
  457. #define DADDR(m_ip) (_disassemble_addr(p_class, func, code[ip + m_ip]))
  458. for (int ip = 0; ip < codelen;) {
  459. int incr = 0;
  460. String txt = itos(ip) + " ";
  461. switch (code[ip]) {
  462. case GDScriptFunction::OPCODE_OPERATOR: {
  463. int op = code[ip + 1];
  464. txt += " op ";
  465. String opname = Variant::get_operator_name(Variant::Operator(op));
  466. txt += DADDR(4);
  467. txt += " = ";
  468. txt += DADDR(2);
  469. txt += " " + opname + " ";
  470. txt += DADDR(3);
  471. incr += 5;
  472. } break;
  473. case GDScriptFunction::OPCODE_SET: {
  474. txt += "set ";
  475. txt += DADDR(1);
  476. txt += "[";
  477. txt += DADDR(2);
  478. txt += "]=";
  479. txt += DADDR(3);
  480. incr += 4;
  481. } break;
  482. case GDScriptFunction::OPCODE_GET: {
  483. txt += " get ";
  484. txt += DADDR(3);
  485. txt += "=";
  486. txt += DADDR(1);
  487. txt += "[";
  488. txt += DADDR(2);
  489. txt += "]";
  490. incr += 4;
  491. } break;
  492. case GDScriptFunction::OPCODE_SET_NAMED: {
  493. txt += " set_named ";
  494. txt += DADDR(1);
  495. txt += "[\"";
  496. txt += func.get_global_name(code[ip + 2]);
  497. txt += "\"]=";
  498. txt += DADDR(3);
  499. incr += 4;
  500. } break;
  501. case GDScriptFunction::OPCODE_GET_NAMED: {
  502. txt += " get_named ";
  503. txt += DADDR(3);
  504. txt += "=";
  505. txt += DADDR(1);
  506. txt += "[\"";
  507. txt += func.get_global_name(code[ip + 2]);
  508. txt += "\"]";
  509. incr += 4;
  510. } break;
  511. case GDScriptFunction::OPCODE_SET_MEMBER: {
  512. txt += " set_member ";
  513. txt += "[\"";
  514. txt += func.get_global_name(code[ip + 1]);
  515. txt += "\"]=";
  516. txt += DADDR(2);
  517. incr += 3;
  518. } break;
  519. case GDScriptFunction::OPCODE_GET_MEMBER: {
  520. txt += " get_member ";
  521. txt += DADDR(2);
  522. txt += "=";
  523. txt += "[\"";
  524. txt += func.get_global_name(code[ip + 1]);
  525. txt += "\"]";
  526. incr += 3;
  527. } break;
  528. case GDScriptFunction::OPCODE_ASSIGN: {
  529. txt += " assign ";
  530. txt += DADDR(1);
  531. txt += "=";
  532. txt += DADDR(2);
  533. incr += 3;
  534. } break;
  535. case GDScriptFunction::OPCODE_ASSIGN_TRUE: {
  536. txt += " assign ";
  537. txt += DADDR(1);
  538. txt += "= true";
  539. incr += 2;
  540. } break;
  541. case GDScriptFunction::OPCODE_ASSIGN_FALSE: {
  542. txt += " assign ";
  543. txt += DADDR(1);
  544. txt += "= false";
  545. incr += 2;
  546. } break;
  547. case GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN: {
  548. txt += " assign typed builtin (";
  549. txt += Variant::get_type_name((Variant::Type)code[ip + 1]);
  550. txt += ") ";
  551. txt += DADDR(2);
  552. txt += " = ";
  553. txt += DADDR(3);
  554. incr += 4;
  555. } break;
  556. case GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE: {
  557. Variant className = func.get_constant(code[ip + 1]);
  558. GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(className.operator Object *());
  559. txt += " assign typed native (";
  560. txt += nc->get_name().operator String();
  561. txt += ") ";
  562. txt += DADDR(2);
  563. txt += " = ";
  564. txt += DADDR(3);
  565. incr += 4;
  566. } break;
  567. case GDScriptFunction::OPCODE_CAST_TO_SCRIPT: {
  568. txt += " cast ";
  569. txt += DADDR(3);
  570. txt += "=";
  571. txt += DADDR(1);
  572. txt += " as ";
  573. txt += DADDR(2);
  574. incr += 4;
  575. } break;
  576. case GDScriptFunction::OPCODE_CONSTRUCT: {
  577. Variant::Type t = Variant::Type(code[ip + 1]);
  578. int argc = code[ip + 2];
  579. txt += " construct ";
  580. txt += DADDR(3 + argc);
  581. txt += " = ";
  582. txt += Variant::get_type_name(t) + "(";
  583. for (int i = 0; i < argc; i++) {
  584. if (i > 0)
  585. txt += ", ";
  586. txt += DADDR(i + 3);
  587. }
  588. txt += ")";
  589. incr = 4 + argc;
  590. } break;
  591. case GDScriptFunction::OPCODE_CONSTRUCT_ARRAY: {
  592. int argc = code[ip + 1];
  593. txt += " make_array ";
  594. txt += DADDR(2 + argc);
  595. txt += " = [ ";
  596. for (int i = 0; i < argc; i++) {
  597. if (i > 0)
  598. txt += ", ";
  599. txt += DADDR(2 + i);
  600. }
  601. txt += "]";
  602. incr += 3 + argc;
  603. } break;
  604. case GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY: {
  605. int argc = code[ip + 1];
  606. txt += " make_dict ";
  607. txt += DADDR(2 + argc * 2);
  608. txt += " = { ";
  609. for (int i = 0; i < argc; i++) {
  610. if (i > 0)
  611. txt += ", ";
  612. txt += DADDR(2 + i * 2 + 0);
  613. txt += ":";
  614. txt += DADDR(2 + i * 2 + 1);
  615. }
  616. txt += "}";
  617. incr += 3 + argc * 2;
  618. } break;
  619. case GDScriptFunction::OPCODE_CALL:
  620. case GDScriptFunction::OPCODE_CALL_RETURN: {
  621. bool ret = code[ip] == GDScriptFunction::OPCODE_CALL_RETURN;
  622. if (ret)
  623. txt += " call-ret ";
  624. else
  625. txt += " call ";
  626. int argc = code[ip + 1];
  627. if (ret) {
  628. txt += DADDR(4 + argc) + "=";
  629. }
  630. txt += DADDR(2) + ".";
  631. txt += String(func.get_global_name(code[ip + 3]));
  632. txt += "(";
  633. for (int i = 0; i < argc; i++) {
  634. if (i > 0)
  635. txt += ", ";
  636. txt += DADDR(4 + i);
  637. }
  638. txt += ")";
  639. incr = 5 + argc;
  640. } break;
  641. case GDScriptFunction::OPCODE_CALL_BUILT_IN: {
  642. txt += " call-built-in ";
  643. int argc = code[ip + 2];
  644. txt += DADDR(3 + argc) + "=";
  645. txt += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(code[ip + 1]));
  646. txt += "(";
  647. for (int i = 0; i < argc; i++) {
  648. if (i > 0)
  649. txt += ", ";
  650. txt += DADDR(3 + i);
  651. }
  652. txt += ")";
  653. incr = 4 + argc;
  654. } break;
  655. case GDScriptFunction::OPCODE_CALL_SELF_BASE: {
  656. txt += " call-self-base ";
  657. int argc = code[ip + 2];
  658. txt += DADDR(3 + argc) + "=";
  659. txt += func.get_global_name(code[ip + 1]);
  660. txt += "(";
  661. for (int i = 0; i < argc; i++) {
  662. if (i > 0)
  663. txt += ", ";
  664. txt += DADDR(3 + i);
  665. }
  666. txt += ")";
  667. incr = 4 + argc;
  668. } break;
  669. case GDScriptFunction::OPCODE_YIELD: {
  670. txt += " yield ";
  671. incr = 1;
  672. } break;
  673. case GDScriptFunction::OPCODE_YIELD_SIGNAL: {
  674. txt += " yield_signal ";
  675. txt += DADDR(1);
  676. txt += ",";
  677. txt += DADDR(2);
  678. incr = 3;
  679. } break;
  680. case GDScriptFunction::OPCODE_YIELD_RESUME: {
  681. txt += " yield resume: ";
  682. txt += DADDR(1);
  683. incr = 2;
  684. } break;
  685. case GDScriptFunction::OPCODE_JUMP: {
  686. txt += " jump ";
  687. txt += itos(code[ip + 1]);
  688. incr = 2;
  689. } break;
  690. case GDScriptFunction::OPCODE_JUMP_IF: {
  691. txt += " jump-if ";
  692. txt += DADDR(1);
  693. txt += " to ";
  694. txt += itos(code[ip + 2]);
  695. incr = 3;
  696. } break;
  697. case GDScriptFunction::OPCODE_JUMP_IF_NOT: {
  698. txt += " jump-if-not ";
  699. txt += DADDR(1);
  700. txt += " to ";
  701. txt += itos(code[ip + 2]);
  702. incr = 3;
  703. } break;
  704. case GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: {
  705. txt += " jump-to-default-argument ";
  706. incr = 1;
  707. } break;
  708. case GDScriptFunction::OPCODE_RETURN: {
  709. txt += " return ";
  710. txt += DADDR(1);
  711. incr = 2;
  712. } break;
  713. case GDScriptFunction::OPCODE_ITERATE_BEGIN: {
  714. txt += " for-init " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
  715. incr += 5;
  716. } break;
  717. case GDScriptFunction::OPCODE_ITERATE: {
  718. txt += " for-loop " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
  719. incr += 5;
  720. } break;
  721. case GDScriptFunction::OPCODE_LINE: {
  722. int line = code[ip + 1] - 1;
  723. if (line >= 0 && line < p_code.size())
  724. txt = "\n" + itos(line + 1) + ": " + p_code[line] + "\n";
  725. else
  726. txt = "";
  727. incr += 2;
  728. } break;
  729. case GDScriptFunction::OPCODE_END: {
  730. txt += " end";
  731. incr += 1;
  732. } break;
  733. case GDScriptFunction::OPCODE_ASSERT: {
  734. txt += " assert ";
  735. txt += DADDR(1);
  736. incr += 2;
  737. } break;
  738. }
  739. if (incr == 0) {
  740. ERR_BREAK_MSG(true, "Unhandled opcode: " + itos(code[ip]));
  741. }
  742. ip += incr;
  743. if (txt != "")
  744. print_line(txt);
  745. }
  746. }
  747. }
  748. MainLoop *test(TestType p_type) {
  749. List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
  750. if (cmdlargs.empty()) {
  751. return nullptr;
  752. }
  753. String test = cmdlargs.back()->get();
  754. if (!test.ends_with(".gd") && !test.ends_with(".gdc")) {
  755. print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test);
  756. return nullptr;
  757. }
  758. FileAccess *fa = FileAccess::open(test, FileAccess::READ);
  759. ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
  760. Vector<uint8_t> buf;
  761. int flen = fa->get_len();
  762. buf.resize(fa->get_len() + 1);
  763. fa->get_buffer(buf.ptrw(), flen);
  764. buf.write[flen] = 0;
  765. String code;
  766. code.parse_utf8((const char *)&buf[0]);
  767. Vector<String> lines;
  768. int last = 0;
  769. for (int i = 0; i <= code.length(); i++) {
  770. if (code[i] == '\n' || code[i] == 0) {
  771. lines.push_back(code.substr(last, i - last));
  772. last = i + 1;
  773. }
  774. }
  775. if (p_type == TEST_TOKENIZER) {
  776. GDScriptTokenizerText tk;
  777. tk.set_code(code);
  778. int line = -1;
  779. while (tk.get_token() != GDScriptTokenizer::TK_EOF) {
  780. String text;
  781. if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER)
  782. text = "'" + tk.get_token_identifier() + "' (identifier)";
  783. else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) {
  784. const Variant &c = tk.get_token_constant();
  785. if (c.get_type() == Variant::STRING)
  786. text = "\"" + String(c) + "\"";
  787. else
  788. text = c;
  789. text = text + " (" + Variant::get_type_name(c.get_type()) + " constant)";
  790. } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR)
  791. text = "ERROR: " + tk.get_token_error();
  792. else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE)
  793. text = "newline (" + itos(tk.get_token_line()) + ") + indent: " + itos(tk.get_token_line_indent());
  794. else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC)
  795. text = "'" + String(GDScriptFunctions::get_func_name(tk.get_token_built_in_func())) + "' (built-in function)";
  796. else
  797. text = tk.get_token_name(tk.get_token());
  798. if (tk.get_token_line() != line) {
  799. int from = line + 1;
  800. line = tk.get_token_line();
  801. for (int i = from; i <= line; i++) {
  802. int l = i - 1;
  803. if (l >= 0 && l < lines.size()) {
  804. print_line("\n" + itos(i) + ": " + lines[l] + "\n");
  805. }
  806. }
  807. }
  808. print_line("\t(" + itos(tk.get_token_column()) + "): " + text);
  809. tk.advance();
  810. }
  811. }
  812. if (p_type == TEST_PARSER) {
  813. GDScriptParser parser;
  814. Error err = parser.parse(code);
  815. if (err) {
  816. print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
  817. memdelete(fa);
  818. return nullptr;
  819. }
  820. const GDScriptParser::Node *root = parser.get_parse_tree();
  821. ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, nullptr);
  822. const GDScriptParser::ClassNode *cnode = static_cast<const GDScriptParser::ClassNode *>(root);
  823. _parser_show_class(cnode, 0, lines);
  824. }
  825. if (p_type == TEST_COMPILER) {
  826. GDScriptParser parser;
  827. Error err = parser.parse(code);
  828. if (err) {
  829. print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
  830. memdelete(fa);
  831. return nullptr;
  832. }
  833. Ref<GDScript> gds;
  834. gds.instance();
  835. GDScriptCompiler gdc;
  836. err = gdc.compile(&parser, gds.ptr());
  837. if (err) {
  838. print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error());
  839. return nullptr;
  840. }
  841. Ref<GDScript> current = gds;
  842. while (current.is_valid()) {
  843. print_line("** CLASS **");
  844. _disassemble_class(current, lines);
  845. current = current->get_base();
  846. }
  847. } else if (p_type == TEST_BYTECODE) {
  848. Vector<uint8_t> buf2 = GDScriptTokenizerBuffer::parse_code_string(code);
  849. String dst = test.get_basename() + ".gdc";
  850. FileAccess *fw = FileAccess::open(dst, FileAccess::WRITE);
  851. fw->store_buffer(buf2.ptr(), buf2.size());
  852. memdelete(fw);
  853. }
  854. memdelete(fa);
  855. return nullptr;
  856. }
  857. } // namespace TestGDScript
  858. #else
  859. namespace TestGDScript {
  860. MainLoop *test(TestType p_type) {
  861. ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used.");
  862. return nullptr;
  863. }
  864. } // namespace TestGDScript
  865. #endif