1 /*************************************************************************/
2 /*  test_gdscript.cpp                                                    */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
9 /*                                                                       */
10 /* Permission is hereby granted, free of charge, to any person obtaining */
11 /* a copy of this software and associated documentation files (the       */
12 /* "Software"), to deal in the Software without restriction, including   */
13 /* without limitation the rights to use, copy, modify, merge, publish,   */
14 /* distribute, sublicense, and/or sell copies of the Software, and to    */
15 /* permit persons to whom the Software is furnished to do so, subject to */
16 /* the following conditions:                                             */
17 /*                                                                       */
18 /* The above copyright notice and this permission notice shall be        */
19 /* included in all copies or substantial portions of the Software.       */
20 /*                                                                       */
21 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
22 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
23 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
24 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
25 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
26 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
27 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
28 /*************************************************************************/
29 #include "test_gdscript.h"
30 
31 #include "os/file_access.h"
32 #include "os/main_loop.h"
33 #include "os/os.h"
34 
35 #ifdef GDSCRIPT_ENABLED
36 
37 #include "modules/gdscript/gd_compiler.h"
38 #include "modules/gdscript/gd_parser.h"
39 #include "modules/gdscript/gd_script.h"
40 #include "modules/gdscript/gd_tokenizer.h"
41 
42 namespace TestGDScript {
43 
_print_indent(int p_ident,const String & p_text)44 static void _print_indent(int p_ident, const String &p_text) {
45 
46 	String txt;
47 	for (int i = 0; i < p_ident; i++) {
48 		txt += '\t';
49 	}
50 
51 	print_line(txt + p_text);
52 }
53 
_parser_extends(const GDParser::ClassNode * p_class)54 static String _parser_extends(const GDParser::ClassNode *p_class) {
55 
56 	String txt = "extends ";
57 	if (String(p_class->extends_file) != "") {
58 		txt += "\"" + p_class->extends_file + "\"";
59 		if (p_class->extends_class.size())
60 			txt += ".";
61 	}
62 
63 	for (int i = 0; i < p_class->extends_class.size(); i++) {
64 
65 		if (i != 0)
66 			txt += ".";
67 
68 		txt += p_class->extends_class[i];
69 	}
70 
71 	return txt;
72 }
73 
_parser_expr(const GDParser::Node * p_expr)74 static String _parser_expr(const GDParser::Node *p_expr) {
75 
76 	String txt;
77 	switch (p_expr->type) {
78 
79 		case GDParser::Node::TYPE_IDENTIFIER: {
80 
81 			const GDParser::IdentifierNode *id_node = static_cast<const GDParser::IdentifierNode *>(p_expr);
82 			txt = id_node->name;
83 		} break;
84 		case GDParser::Node::TYPE_CONSTANT: {
85 			const GDParser::ConstantNode *c_node = static_cast<const GDParser::ConstantNode *>(p_expr);
86 			if (c_node->value.get_type() == Variant::STRING)
87 				txt = "\"" + String(c_node->value) + "\"";
88 			else
89 				txt = c_node->value;
90 
91 		} break;
92 		case GDParser::Node::TYPE_SELF: {
93 			txt = "self";
94 		} break;
95 		case GDParser::Node::TYPE_ARRAY: {
96 			const GDParser::ArrayNode *arr_node = static_cast<const GDParser::ArrayNode *>(p_expr);
97 			txt += "[";
98 			for (int i = 0; i < arr_node->elements.size(); i++) {
99 
100 				if (i > 0)
101 					txt += ", ";
102 				txt += _parser_expr(arr_node->elements[i]);
103 			}
104 			txt += "]";
105 		} break;
106 		case GDParser::Node::TYPE_DICTIONARY: {
107 			const GDParser::DictionaryNode *dict_node = static_cast<const GDParser::DictionaryNode *>(p_expr);
108 			txt += "{";
109 			for (int i = 0; i < dict_node->elements.size(); i++) {
110 
111 				if (i > 0)
112 					txt += ", ";
113 
114 				const GDParser::DictionaryNode::Pair &p = dict_node->elements[i];
115 				txt += _parser_expr(p.key);
116 				txt += ":";
117 				txt += _parser_expr(p.value);
118 			}
119 			txt += "}";
120 		} break;
121 		case GDParser::Node::TYPE_OPERATOR: {
122 
123 			const GDParser::OperatorNode *c_node = static_cast<const GDParser::OperatorNode *>(p_expr);
124 			switch (c_node->op) {
125 
126 				case GDParser::OperatorNode::OP_PARENT_CALL:
127 					txt += ".";
128 				case GDParser::OperatorNode::OP_CALL: {
129 
130 					ERR_FAIL_COND_V(c_node->arguments.size() < 1, "");
131 					String func_name;
132 					const GDParser::Node *nfunc = c_node->arguments[0];
133 					int arg_ofs = 0;
134 					if (nfunc->type == GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
135 
136 						const GDParser::BuiltInFunctionNode *bif_node = static_cast<const GDParser::BuiltInFunctionNode *>(nfunc);
137 						func_name = GDFunctions::get_func_name(bif_node->function);
138 						arg_ofs = 1;
139 					} else if (nfunc->type == GDParser::Node::TYPE_TYPE) {
140 
141 						const GDParser::TypeNode *t_node = static_cast<const GDParser::TypeNode *>(nfunc);
142 						func_name = Variant::get_type_name(t_node->vtype);
143 						arg_ofs = 1;
144 					} else {
145 
146 						ERR_FAIL_COND_V(c_node->arguments.size() < 2, "");
147 						nfunc = c_node->arguments[1];
148 						ERR_FAIL_COND_V(nfunc->type != GDParser::Node::TYPE_IDENTIFIER, "");
149 
150 						if (c_node->arguments[0]->type != GDParser::Node::TYPE_SELF)
151 							func_name = _parser_expr(c_node->arguments[0]) + ".";
152 
153 						func_name += _parser_expr(nfunc);
154 						arg_ofs = 2;
155 					}
156 
157 					txt += func_name + "(";
158 
159 					for (int i = arg_ofs; i < c_node->arguments.size(); i++) {
160 
161 						const GDParser::Node *arg = c_node->arguments[i];
162 						if (i > arg_ofs)
163 							txt += ", ";
164 						txt += _parser_expr(arg);
165 					}
166 
167 					txt += ")";
168 
169 				} break;
170 				case GDParser::OperatorNode::OP_INDEX: {
171 
172 					ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
173 
174 					//index with []
175 					txt = _parser_expr(c_node->arguments[0]) + "[" + _parser_expr(c_node->arguments[1]) + "]";
176 
177 				} break;
178 				case GDParser::OperatorNode::OP_INDEX_NAMED: {
179 
180 					ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
181 
182 					txt = _parser_expr(c_node->arguments[0]) + "." + _parser_expr(c_node->arguments[1]);
183 
184 				} break;
185 				case GDParser::OperatorNode::OP_NEG: {
186 					txt = "-" + _parser_expr(c_node->arguments[0]);
187 				} break;
188 				case GDParser::OperatorNode::OP_NOT: {
189 					txt = "not " + _parser_expr(c_node->arguments[0]);
190 				} break;
191 				case GDParser::OperatorNode::OP_BIT_INVERT: {
192 					txt = "~" + _parser_expr(c_node->arguments[0]);
193 				} break;
194 				case GDParser::OperatorNode::OP_PREINC: {
195 				} break;
196 				case GDParser::OperatorNode::OP_PREDEC: {
197 				} break;
198 				case GDParser::OperatorNode::OP_INC: {
199 				} break;
200 				case GDParser::OperatorNode::OP_DEC: {
201 				} break;
202 				case GDParser::OperatorNode::OP_IN: {
203 					txt = _parser_expr(c_node->arguments[0]) + " in " + _parser_expr(c_node->arguments[1]);
204 				} break;
205 				case GDParser::OperatorNode::OP_EQUAL: {
206 					txt = _parser_expr(c_node->arguments[0]) + "==" + _parser_expr(c_node->arguments[1]);
207 				} break;
208 				case GDParser::OperatorNode::OP_NOT_EQUAL: {
209 					txt = _parser_expr(c_node->arguments[0]) + "!=" + _parser_expr(c_node->arguments[1]);
210 				} break;
211 				case GDParser::OperatorNode::OP_LESS: {
212 					txt = _parser_expr(c_node->arguments[0]) + "<" + _parser_expr(c_node->arguments[1]);
213 				} break;
214 				case GDParser::OperatorNode::OP_LESS_EQUAL: {
215 					txt = _parser_expr(c_node->arguments[0]) + "<=" + _parser_expr(c_node->arguments[1]);
216 				} break;
217 				case GDParser::OperatorNode::OP_GREATER: {
218 					txt = _parser_expr(c_node->arguments[0]) + ">" + _parser_expr(c_node->arguments[1]);
219 				} break;
220 				case GDParser::OperatorNode::OP_GREATER_EQUAL: {
221 					txt = _parser_expr(c_node->arguments[0]) + ">=" + _parser_expr(c_node->arguments[1]);
222 				} break;
223 				case GDParser::OperatorNode::OP_AND: {
224 					txt = _parser_expr(c_node->arguments[0]) + " and " + _parser_expr(c_node->arguments[1]);
225 				} break;
226 				case GDParser::OperatorNode::OP_OR: {
227 					txt = _parser_expr(c_node->arguments[0]) + " or " + _parser_expr(c_node->arguments[1]);
228 				} break;
229 				case GDParser::OperatorNode::OP_ADD: {
230 					txt = _parser_expr(c_node->arguments[0]) + "+" + _parser_expr(c_node->arguments[1]);
231 				} break;
232 				case GDParser::OperatorNode::OP_SUB: {
233 					txt = _parser_expr(c_node->arguments[0]) + "-" + _parser_expr(c_node->arguments[1]);
234 				} break;
235 				case GDParser::OperatorNode::OP_MUL: {
236 					txt = _parser_expr(c_node->arguments[0]) + "*" + _parser_expr(c_node->arguments[1]);
237 				} break;
238 				case GDParser::OperatorNode::OP_DIV: {
239 					txt = _parser_expr(c_node->arguments[0]) + "/" + _parser_expr(c_node->arguments[1]);
240 				} break;
241 				case GDParser::OperatorNode::OP_MOD: {
242 					txt = _parser_expr(c_node->arguments[0]) + "%" + _parser_expr(c_node->arguments[1]);
243 				} break;
244 				case GDParser::OperatorNode::OP_SHIFT_LEFT: {
245 					txt = _parser_expr(c_node->arguments[0]) + "<<" + _parser_expr(c_node->arguments[1]);
246 				} break;
247 				case GDParser::OperatorNode::OP_SHIFT_RIGHT: {
248 					txt = _parser_expr(c_node->arguments[0]) + ">>" + _parser_expr(c_node->arguments[1]);
249 				} break;
250 				case GDParser::OperatorNode::OP_ASSIGN: {
251 					txt = _parser_expr(c_node->arguments[0]) + "=" + _parser_expr(c_node->arguments[1]);
252 				} break;
253 				case GDParser::OperatorNode::OP_ASSIGN_ADD: {
254 					txt = _parser_expr(c_node->arguments[0]) + "+=" + _parser_expr(c_node->arguments[1]);
255 				} break;
256 				case GDParser::OperatorNode::OP_ASSIGN_SUB: {
257 					txt = _parser_expr(c_node->arguments[0]) + "-=" + _parser_expr(c_node->arguments[1]);
258 				} break;
259 				case GDParser::OperatorNode::OP_ASSIGN_MUL: {
260 					txt = _parser_expr(c_node->arguments[0]) + "*=" + _parser_expr(c_node->arguments[1]);
261 				} break;
262 				case GDParser::OperatorNode::OP_ASSIGN_DIV: {
263 					txt = _parser_expr(c_node->arguments[0]) + "/=" + _parser_expr(c_node->arguments[1]);
264 				} break;
265 				case GDParser::OperatorNode::OP_ASSIGN_MOD: {
266 					txt = _parser_expr(c_node->arguments[0]) + "%=" + _parser_expr(c_node->arguments[1]);
267 				} break;
268 				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: {
269 					txt = _parser_expr(c_node->arguments[0]) + "<<=" + _parser_expr(c_node->arguments[1]);
270 				} break;
271 				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: {
272 					txt = _parser_expr(c_node->arguments[0]) + ">>=" + _parser_expr(c_node->arguments[1]);
273 				} break;
274 				case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: {
275 					txt = _parser_expr(c_node->arguments[0]) + "&=" + _parser_expr(c_node->arguments[1]);
276 				} break;
277 				case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: {
278 					txt = _parser_expr(c_node->arguments[0]) + "|=" + _parser_expr(c_node->arguments[1]);
279 				} break;
280 				case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: {
281 					txt = _parser_expr(c_node->arguments[0]) + "^=" + _parser_expr(c_node->arguments[1]);
282 				} break;
283 				case GDParser::OperatorNode::OP_BIT_AND: {
284 					txt = _parser_expr(c_node->arguments[0]) + "&" + _parser_expr(c_node->arguments[1]);
285 				} break;
286 				case GDParser::OperatorNode::OP_BIT_OR: {
287 					txt = _parser_expr(c_node->arguments[0]) + "|" + _parser_expr(c_node->arguments[1]);
288 				} break;
289 				case GDParser::OperatorNode::OP_BIT_XOR: {
290 					txt = _parser_expr(c_node->arguments[0]) + "^" + _parser_expr(c_node->arguments[1]);
291 				} break;
292 			}
293 
294 		} break;
295 		case GDParser::Node::TYPE_NEWLINE: {
296 
297 			//skippie
298 		} break;
299 		default: {
300 
301 			String error = "Parser bug at " + itos(p_expr->line) + ", invalid expression type: " + itos(p_expr->type);
302 			ERR_EXPLAIN(error);
303 			ERR_FAIL_V("");
304 		}
305 	}
306 
307 	return txt;
308 	//return "("+txt+")";
309 }
310 
_parser_show_block(const GDParser::BlockNode * p_block,int p_indent)311 static void _parser_show_block(const GDParser::BlockNode *p_block, int p_indent) {
312 
313 	for (int i = 0; i < p_block->statements.size(); i++) {
314 
315 		const GDParser::Node *statement = p_block->statements[i];
316 
317 		switch (statement->type) {
318 
319 			case GDParser::Node::TYPE_CONTROL_FLOW: {
320 
321 				const GDParser::ControlFlowNode *cf_node = static_cast<const GDParser::ControlFlowNode *>(statement);
322 				switch (cf_node->cf_type) {
323 
324 					case GDParser::ControlFlowNode::CF_IF: {
325 
326 						ERR_FAIL_COND(cf_node->arguments.size() != 1);
327 						String txt;
328 						txt += "if ";
329 						txt += _parser_expr(cf_node->arguments[0]);
330 						txt += ":";
331 						_print_indent(p_indent, txt);
332 						ERR_FAIL_COND(!cf_node->body);
333 						_parser_show_block(cf_node->body, p_indent + 1);
334 						if (cf_node->body_else) {
335 							_print_indent(p_indent, "else:");
336 							_parser_show_block(cf_node->body_else, p_indent + 1);
337 						}
338 
339 					} break;
340 					case GDParser::ControlFlowNode::CF_FOR: {
341 						ERR_FAIL_COND(cf_node->arguments.size() != 2);
342 						String txt;
343 						txt += "for ";
344 						txt += _parser_expr(cf_node->arguments[0]);
345 						txt += " in ";
346 						txt += _parser_expr(cf_node->arguments[1]);
347 						txt += ":";
348 						_print_indent(p_indent, txt);
349 						ERR_FAIL_COND(!cf_node->body);
350 						_parser_show_block(cf_node->body, p_indent + 1);
351 
352 					} break;
353 					case GDParser::ControlFlowNode::CF_WHILE: {
354 
355 						ERR_FAIL_COND(cf_node->arguments.size() != 1);
356 						String txt;
357 						txt += "while ";
358 						txt += _parser_expr(cf_node->arguments[0]);
359 						txt += ":";
360 						_print_indent(p_indent, txt);
361 						ERR_FAIL_COND(!cf_node->body);
362 						_parser_show_block(cf_node->body, p_indent + 1);
363 
364 					} break;
365 					case GDParser::ControlFlowNode::CF_SWITCH: {
366 
367 					} break;
368 					case GDParser::ControlFlowNode::CF_CONTINUE: {
369 
370 						_print_indent(p_indent, "continue");
371 					} break;
372 					case GDParser::ControlFlowNode::CF_BREAK: {
373 
374 						_print_indent(p_indent, "break");
375 					} break;
376 					case GDParser::ControlFlowNode::CF_RETURN: {
377 
378 						if (cf_node->arguments.size())
379 							_print_indent(p_indent, "return " + _parser_expr(cf_node->arguments[0]));
380 						else
381 							_print_indent(p_indent, "return ");
382 					} break;
383 				}
384 
385 			} break;
386 			case GDParser::Node::TYPE_LOCAL_VAR: {
387 
388 				const GDParser::LocalVarNode *lv_node = static_cast<const GDParser::LocalVarNode *>(statement);
389 				_print_indent(p_indent, "var " + String(lv_node->name));
390 			} break;
391 			default: {
392 				//expression i guess
393 				_print_indent(p_indent, _parser_expr(statement));
394 			}
395 		}
396 	}
397 }
398 
_parser_show_function(const GDParser::FunctionNode * p_func,int p_indent,GDParser::BlockNode * p_initializer=NULL)399 static void _parser_show_function(const GDParser::FunctionNode *p_func, int p_indent, GDParser::BlockNode *p_initializer = NULL) {
400 
401 	String txt;
402 	if (p_func->_static)
403 		txt = "static ";
404 	txt += "func ";
405 	if (p_func->name == "") // initializer
406 		txt += "[built-in-initializer]";
407 	else
408 		txt += String(p_func->name);
409 	txt += "(";
410 
411 	for (int i = 0; i < p_func->arguments.size(); i++) {
412 
413 		if (i != 0)
414 			txt += ", ";
415 		txt += "var " + String(p_func->arguments[i]);
416 		if (i >= (p_func->arguments.size() - p_func->default_values.size())) {
417 			int defarg = i - (p_func->arguments.size() - p_func->default_values.size());
418 			txt += "=";
419 			txt += _parser_expr(p_func->default_values[defarg]);
420 		}
421 	}
422 
423 	txt += ")";
424 
425 	//todo constructor check!
426 
427 	txt += ":";
428 
429 	_print_indent(p_indent, txt);
430 	if (p_initializer)
431 		_parser_show_block(p_initializer, p_indent + 1);
432 	_parser_show_block(p_func->body, p_indent + 1);
433 }
434 
_parser_show_class(const GDParser::ClassNode * p_class,int p_indent,const Vector<String> & p_code)435 static void _parser_show_class(const GDParser::ClassNode *p_class, int p_indent, const Vector<String> &p_code) {
436 
437 	if (p_indent == 0 && (String(p_class->extends_file) != "" || p_class->extends_class.size())) {
438 
439 		_print_indent(p_indent, _parser_extends(p_class));
440 		print_line("\n");
441 	}
442 
443 	for (int i = 0; i < p_class->subclasses.size(); i++) {
444 
445 		const GDParser::ClassNode *subclass = p_class->subclasses[i];
446 		String line = "class " + subclass->name;
447 		if (String(subclass->extends_file) != "" || subclass->extends_class.size())
448 			line += " " + _parser_extends(subclass);
449 		line += ":";
450 		_print_indent(p_indent, line);
451 		_parser_show_class(subclass, p_indent + 1, p_code);
452 		print_line("\n");
453 	}
454 
455 	for (int i = 0; i < p_class->constant_expressions.size(); i++) {
456 
457 		const GDParser::ClassNode::Constant &constant = p_class->constant_expressions[i];
458 		_print_indent(p_indent, "const " + String(constant.identifier) + "=" + _parser_expr(constant.expression));
459 	}
460 
461 	for (int i = 0; i < p_class->variables.size(); i++) {
462 
463 		const GDParser::ClassNode::Member &m = p_class->variables[i];
464 
465 		_print_indent(p_indent, "var " + String(m.identifier));
466 	}
467 
468 	print_line("\n");
469 
470 	for (int i = 0; i < p_class->static_functions.size(); i++) {
471 
472 		_parser_show_function(p_class->static_functions[i], p_indent);
473 		print_line("\n");
474 	}
475 
476 	for (int i = 0; i < p_class->functions.size(); i++) {
477 
478 		if (String(p_class->functions[i]->name) == "_init") {
479 			_parser_show_function(p_class->functions[i], p_indent, p_class->initializer);
480 		} else
481 			_parser_show_function(p_class->functions[i], p_indent);
482 		print_line("\n");
483 	}
484 	//_parser_show_function(p_class->initializer,p_indent);
485 	print_line("\n");
486 }
487 
_disassemble_addr(const Ref<GDScript> & p_script,const GDFunction & func,int p_addr)488 static String _disassemble_addr(const Ref<GDScript> &p_script, const GDFunction &func, int p_addr) {
489 
490 	int addr = p_addr & GDFunction::ADDR_MASK;
491 
492 	switch (p_addr >> GDFunction::ADDR_BITS) {
493 
494 		case GDFunction::ADDR_TYPE_SELF: {
495 			return "self";
496 		} break;
497 		case GDFunction::ADDR_TYPE_CLASS: {
498 			return "class";
499 		} break;
500 		case GDFunction::ADDR_TYPE_MEMBER: {
501 
502 			return "member(" + p_script->debug_get_member_by_index(addr) + ")";
503 		} break;
504 		case GDFunction::ADDR_TYPE_CLASS_CONSTANT: {
505 
506 			return "class_const(" + func.get_global_name(addr) + ")";
507 		} break;
508 		case GDFunction::ADDR_TYPE_LOCAL_CONSTANT: {
509 
510 			Variant v = func.get_constant(addr);
511 			String txt;
512 			if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH)
513 				txt = "\"" + String(v) + "\"";
514 			else
515 				txt = v;
516 			return "const(" + txt + ")";
517 		} break;
518 		case GDFunction::ADDR_TYPE_STACK: {
519 
520 			return "stack(" + itos(addr) + ")";
521 		} break;
522 		case GDFunction::ADDR_TYPE_STACK_VARIABLE: {
523 
524 			return "var_stack(" + itos(addr) + ")";
525 		} break;
526 		case GDFunction::ADDR_TYPE_GLOBAL: {
527 
528 			return "global(" + func.get_global_name(addr) + ")";
529 		} break;
530 		case GDFunction::ADDR_TYPE_NIL: {
531 			return "nil";
532 		} break;
533 	}
534 
535 	return "<err>";
536 }
537 
_disassemble_class(const Ref<GDScript> & p_class,const Vector<String> & p_code)538 static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String> &p_code) {
539 
540 	const Map<StringName, GDFunction *> &mf = p_class->debug_get_member_functions();
541 
542 	for (const Map<StringName, GDFunction *>::Element *E = mf.front(); E; E = E->next()) {
543 
544 		const GDFunction &func = *E->get();
545 		const int *code = func.get_code();
546 		int codelen = func.get_code_size();
547 		String defargs;
548 		if (func.get_default_argument_count()) {
549 			defargs = "defarg at: ";
550 			for (int i = 0; i < func.get_default_argument_count(); i++) {
551 
552 				if (i > 0)
553 					defargs += ",";
554 				defargs += itos(func.get_default_argument_addr(i));
555 			}
556 			defargs += " ";
557 		}
558 		print_line("== function " + String(func.get_name()) + "() :: stack size: " + itos(func.get_max_stack_size()) + " " + defargs + "==");
559 
560 #define DADDR(m_ip) (_disassemble_addr(p_class, func, code[ip + m_ip]))
561 
562 		for (int ip = 0; ip < codelen;) {
563 
564 			int incr = 0;
565 			String txt = itos(ip) + " ";
566 
567 			switch (code[ip]) {
568 
569 				case GDFunction::OPCODE_OPERATOR: {
570 
571 					int op = code[ip + 1];
572 					txt += "op ";
573 
574 					String opname = Variant::get_operator_name(Variant::Operator(op));
575 
576 					txt += DADDR(4);
577 					txt += " = ";
578 					txt += DADDR(2);
579 					txt += " " + opname + " ";
580 					txt += DADDR(3);
581 					incr += 5;
582 
583 				} break;
584 				case GDFunction::OPCODE_SET: {
585 
586 					txt += "set ";
587 					txt += DADDR(1);
588 					txt += "[";
589 					txt += DADDR(2);
590 					txt += "]=";
591 					txt += DADDR(3);
592 					incr += 4;
593 
594 				} break;
595 				case GDFunction::OPCODE_GET: {
596 
597 					txt += " get ";
598 					txt += DADDR(3);
599 					txt += "=";
600 					txt += DADDR(1);
601 					txt += "[";
602 					txt += DADDR(2);
603 					txt += "]";
604 					incr += 4;
605 
606 				} break;
607 				case GDFunction::OPCODE_SET_NAMED: {
608 
609 					txt += " set_named ";
610 					txt += DADDR(1);
611 					txt += "[\"";
612 					txt += func.get_global_name(code[ip + 2]);
613 					txt += "\"]=";
614 					txt += DADDR(3);
615 					incr += 4;
616 
617 				} break;
618 				case GDFunction::OPCODE_GET_NAMED: {
619 
620 					txt += " get_named ";
621 					txt += DADDR(3);
622 					txt += "=";
623 					txt += DADDR(1);
624 					txt += "[\"";
625 					txt += func.get_global_name(code[ip + 2]);
626 					txt += "\"]";
627 					incr += 4;
628 
629 				} break;
630 				case GDFunction::OPCODE_ASSIGN: {
631 
632 					txt += " assign ";
633 					txt += DADDR(1);
634 					txt += "=";
635 					txt += DADDR(2);
636 					incr += 3;
637 
638 				} break;
639 				case GDFunction::OPCODE_ASSIGN_TRUE: {
640 
641 					txt += " assign ";
642 					txt += DADDR(1);
643 					txt += "= true";
644 					incr += 2;
645 
646 				} break;
647 				case GDFunction::OPCODE_ASSIGN_FALSE: {
648 
649 					txt += " assign ";
650 					txt += DADDR(1);
651 					txt += "= false";
652 					incr += 2;
653 
654 				} break;
655 				case GDFunction::OPCODE_CONSTRUCT: {
656 
657 					Variant::Type t = Variant::Type(code[ip + 1]);
658 					int argc = code[ip + 2];
659 
660 					txt += " construct ";
661 					txt += DADDR(3 + argc);
662 					txt += " = ";
663 
664 					txt += Variant::get_type_name(t) + "(";
665 					for (int i = 0; i < argc; i++) {
666 
667 						if (i > 0)
668 							txt += ", ";
669 						txt += DADDR(i + 3);
670 					}
671 					txt += ")";
672 
673 					incr = 4 + argc;
674 
675 				} break;
676 				case GDFunction::OPCODE_CONSTRUCT_ARRAY: {
677 
678 					int argc = code[ip + 1];
679 					txt += " make_array ";
680 					txt += DADDR(2 + argc);
681 					txt += " = [ ";
682 
683 					for (int i = 0; i < argc; i++) {
684 						if (i > 0)
685 							txt += ", ";
686 						txt += DADDR(2 + i);
687 					}
688 
689 					txt += "]";
690 
691 					incr += 3 + argc;
692 
693 				} break;
694 				case GDFunction::OPCODE_CONSTRUCT_DICTIONARY: {
695 
696 					int argc = code[ip + 1];
697 					txt += " make_dict ";
698 					txt += DADDR(2 + argc * 2);
699 					txt += " = { ";
700 
701 					for (int i = 0; i < argc; i++) {
702 						if (i > 0)
703 							txt += ", ";
704 						txt += DADDR(2 + i * 2 + 0);
705 						txt += ":";
706 						txt += DADDR(2 + i * 2 + 1);
707 					}
708 
709 					txt += "}";
710 
711 					incr += 3 + argc * 2;
712 
713 				} break;
714 
715 				case GDFunction::OPCODE_CALL:
716 				case GDFunction::OPCODE_CALL_RETURN: {
717 
718 					bool ret = code[ip] == GDFunction::OPCODE_CALL_RETURN;
719 
720 					if (ret)
721 						txt += " call-ret ";
722 					else
723 						txt += " call ";
724 
725 					int argc = code[ip + 1];
726 					if (ret) {
727 						txt += DADDR(4 + argc) + "=";
728 					}
729 
730 					txt += DADDR(2) + ".";
731 					txt += String(func.get_global_name(code[ip + 3]));
732 					txt += "(";
733 
734 					for (int i = 0; i < argc; i++) {
735 						if (i > 0)
736 							txt += ", ";
737 						txt += DADDR(4 + i);
738 					}
739 					txt += ")";
740 
741 					incr = 5 + argc;
742 
743 				} break;
744 				case GDFunction::OPCODE_CALL_BUILT_IN: {
745 
746 					txt += " call-built-in ";
747 
748 					int argc = code[ip + 2];
749 					txt += DADDR(3 + argc) + "=";
750 
751 					txt += GDFunctions::get_func_name(GDFunctions::Function(code[ip + 1]));
752 					txt += "(";
753 
754 					for (int i = 0; i < argc; i++) {
755 						if (i > 0)
756 							txt += ", ";
757 						txt += DADDR(3 + i);
758 					}
759 					txt += ")";
760 
761 					incr = 4 + argc;
762 
763 				} break;
764 				case GDFunction::OPCODE_CALL_SELF_BASE: {
765 
766 					txt += " call-self-base ";
767 
768 					int argc = code[ip + 2];
769 					txt += DADDR(3 + argc) + "=";
770 
771 					txt += func.get_global_name(code[ip + 1]);
772 					txt += "(";
773 
774 					for (int i = 0; i < argc; i++) {
775 						if (i > 0)
776 							txt += ", ";
777 						txt += DADDR(3 + i);
778 					}
779 					txt += ")";
780 
781 					incr = 4 + argc;
782 
783 				} break;
784 				case GDFunction::OPCODE_YIELD: {
785 
786 					txt += " yield ";
787 					incr = 1;
788 
789 				} break;
790 				case GDFunction::OPCODE_YIELD_SIGNAL: {
791 
792 					txt += " yield_signal ";
793 					txt += DADDR(1);
794 					txt += ",";
795 					txt += DADDR(2);
796 					incr = 3;
797 				} break;
798 				case GDFunction::OPCODE_YIELD_RESUME: {
799 
800 					txt += " yield resume: ";
801 					txt += DADDR(1);
802 					incr = 2;
803 				} break;
804 				case GDFunction::OPCODE_JUMP: {
805 
806 					txt += " jump ";
807 					txt += itos(code[ip + 1]);
808 
809 					incr = 2;
810 
811 				} break;
812 				case GDFunction::OPCODE_JUMP_IF: {
813 
814 					txt += " jump-if ";
815 					txt += DADDR(1);
816 					txt += " to ";
817 					txt += itos(code[ip + 2]);
818 
819 					incr = 3;
820 				} break;
821 				case GDFunction::OPCODE_JUMP_IF_NOT: {
822 
823 					txt += " jump-if-not ";
824 					txt += DADDR(1);
825 					txt += " to ";
826 					txt += itos(code[ip + 2]);
827 
828 					incr = 3;
829 				} break;
830 				case GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: {
831 
832 					txt += " jump-to-default-argument ";
833 					incr = 1;
834 				} break;
835 				case GDFunction::OPCODE_RETURN: {
836 
837 					txt += " return ";
838 					txt += DADDR(1);
839 
840 					incr = 2;
841 
842 				} break;
843 				case GDFunction::OPCODE_ITERATE_BEGIN: {
844 
845 					txt += " for-init " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
846 					incr += 5;
847 
848 				} break;
849 				case GDFunction::OPCODE_ITERATE: {
850 
851 					txt += " for-loop " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
852 					incr += 5;
853 
854 				} break;
855 				case GDFunction::OPCODE_LINE: {
856 
857 					int line = code[ip + 1] - 1;
858 					if (line >= 0 && line < p_code.size())
859 						txt = "\n" + itos(line + 1) + ": " + p_code[line] + "\n";
860 					else
861 						txt = "";
862 					incr += 2;
863 				} break;
864 				case GDFunction::OPCODE_END: {
865 
866 					txt += " end";
867 					incr += 1;
868 				} break;
869 				case GDFunction::OPCODE_ASSERT: {
870 
871 					txt += " assert ";
872 					txt += DADDR(1);
873 					incr += 2;
874 
875 				} break;
876 			}
877 
878 			if (incr == 0) {
879 
880 				ERR_EXPLAIN("unhandled opcode: " + itos(code[ip]));
881 				ERR_BREAK(incr == 0);
882 			}
883 
884 			ip += incr;
885 			if (txt != "")
886 				print_line(txt);
887 		}
888 	}
889 }
890 
test(TestType p_test)891 MainLoop *test(TestType p_test) {
892 
893 	List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
894 
895 	if (cmdlargs.empty()) {
896 		//try editor!
897 		return NULL;
898 	}
899 
900 	String test = cmdlargs.back()->get();
901 
902 	FileAccess *fa = FileAccess::open(test, FileAccess::READ);
903 
904 	if (!fa) {
905 		ERR_EXPLAIN("Could not open file: " + test);
906 		ERR_FAIL_V(NULL);
907 	}
908 
909 	Vector<uint8_t> buf;
910 	int flen = fa->get_len();
911 	buf.resize(fa->get_len() + 1);
912 	fa->get_buffer(&buf[0], flen);
913 	buf[flen] = 0;
914 
915 	String code;
916 	code.parse_utf8((const char *)&buf[0]);
917 
918 	Vector<String> lines;
919 	int last = 0;
920 
921 	for (int i = 0; i <= code.length(); i++) {
922 
923 		if (code[i] == '\n' || code[i] == 0) {
924 
925 			lines.push_back(code.substr(last, i - last));
926 			last = i + 1;
927 		}
928 	}
929 
930 	if (p_test == TEST_TOKENIZER) {
931 
932 		GDTokenizerText tk;
933 		tk.set_code(code);
934 		int line = -1;
935 		while (tk.get_token() != GDTokenizer::TK_EOF) {
936 
937 			String text;
938 			if (tk.get_token() == GDTokenizer::TK_IDENTIFIER)
939 				text = "'" + tk.get_token_identifier() + "' (identifier)";
940 			else if (tk.get_token() == GDTokenizer::TK_CONSTANT) {
941 				Variant c = tk.get_token_constant();
942 				if (c.get_type() == Variant::STRING)
943 					text = "\"" + String(c) + "\"";
944 				else
945 					text = c;
946 
947 				text = text + " (" + Variant::get_type_name(c.get_type()) + " constant)";
948 			} else if (tk.get_token() == GDTokenizer::TK_ERROR)
949 				text = "ERROR: " + tk.get_token_error();
950 			else if (tk.get_token() == GDTokenizer::TK_NEWLINE)
951 				text = "newline (" + itos(tk.get_token_line()) + ") + indent: " + itos(tk.get_token_line_indent());
952 			else if (tk.get_token() == GDTokenizer::TK_BUILT_IN_FUNC)
953 				text = "'" + String(GDFunctions::get_func_name(tk.get_token_built_in_func())) + "' (built-in function)";
954 			else
955 				text = tk.get_token_name(tk.get_token());
956 
957 			if (tk.get_token_line() != line) {
958 				int from = line + 1;
959 				line = tk.get_token_line();
960 
961 				for (int i = from; i <= line; i++) {
962 					int l = i - 1;
963 					if (l >= 0 && l < lines.size()) {
964 						print_line("\n" + itos(i) + ": " + lines[l] + "\n");
965 					}
966 				}
967 			}
968 			print_line("\t(" + itos(tk.get_token_column()) + "): " + text);
969 			tk.advance();
970 		}
971 	}
972 
973 	if (p_test == TEST_PARSER) {
974 
975 		GDParser parser;
976 		Error err = parser.parse(code);
977 		if (err) {
978 			print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
979 			memdelete(fa);
980 			return NULL;
981 		}
982 
983 		const GDParser::Node *root = parser.get_parse_tree();
984 		ERR_FAIL_COND_V(root->type != GDParser::Node::TYPE_CLASS, NULL);
985 		const GDParser::ClassNode *cnode = static_cast<const GDParser::ClassNode *>(root);
986 
987 		_parser_show_class(cnode, 0, lines);
988 	}
989 
990 	if (p_test == TEST_COMPILER) {
991 
992 		GDParser parser;
993 
994 		Error err = parser.parse(code);
995 		if (err) {
996 			print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
997 			memdelete(fa);
998 			return NULL;
999 		}
1000 
1001 		GDScript *script = memnew(GDScript);
1002 
1003 		GDCompiler gdc;
1004 		err = gdc.compile(&parser, script);
1005 		if (err) {
1006 
1007 			print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error());
1008 			memdelete(script);
1009 			return NULL;
1010 		}
1011 
1012 		Ref<GDScript> gds = Ref<GDScript>(script);
1013 
1014 		Ref<GDScript> current = gds;
1015 
1016 		while (current.is_valid()) {
1017 
1018 			print_line("** CLASS **");
1019 			_disassemble_class(current, lines);
1020 
1021 			current = current->get_base();
1022 		}
1023 
1024 	} else if (p_test == TEST_BYTECODE) {
1025 
1026 		Vector<uint8_t> buf = GDTokenizerBuffer::parse_code_string(code);
1027 		String dst = test.basename() + ".gdc";
1028 		FileAccess *fw = FileAccess::open(dst, FileAccess::WRITE);
1029 		fw->store_buffer(buf.ptr(), buf.size());
1030 		memdelete(fw);
1031 	}
1032 
1033 #if 0
1034 	Parser parser;
1035 	Error err = parser.parse(code);
1036 	if (err) {
1037 		print_line("error:"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error());
1038 	} else {
1039 		print_line("Parse O-K!");
1040 	}
1041 #endif
1042 
1043 	memdelete(fa);
1044 
1045 	return NULL;
1046 }
1047 } // namespace TestGDScript
1048 
1049 #else
1050 
1051 namespace TestGDScript {
1052 
test(TestType p_test)1053 MainLoop *test(TestType p_test) {
1054 
1055 	return NULL;
1056 }
1057 } // namespace TestGDScript
1058 
1059 #endif
1060