test_gdscript.cpp 30 KB

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