test_gdscript.cpp 30 KB

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