Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/as2js
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #define CATCH_CONFIG_RUNNER
22 : #include "catch_main.h"
23 :
24 :
25 :
26 : // as2js
27 : //
28 : #include <as2js/exception.h>
29 : #include <as2js/version.h>
30 :
31 :
32 : // libexcept
33 : //
34 : #include <libexcept/exception.h>
35 :
36 :
37 : // snapdev
38 : //
39 : #include <snapdev/not_used.h>
40 : #include <snapdev/mkdir_p.h>
41 :
42 :
43 : // C
44 : //
45 : #include <sys/stat.h>
46 :
47 :
48 : // last include
49 : //
50 : #include <snapdev/poison.h>
51 :
52 :
53 :
54 :
55 : namespace SNAP_CATCH2_NAMESPACE
56 : {
57 :
58 :
59 :
60 : #define TO_STR_sub(s) #s
61 :
62 :
63 :
64 : // command line flags
65 : //
66 : std::string g_as2js_compiler;
67 : bool g_run_destructive = false;
68 : bool g_save_parser_tests = false;
69 :
70 :
71 :
72 :
73 :
74 : // class used to capture error messages
75 :
76 1873468 : test_callback::test_callback(bool verbose, bool parser)
77 1873468 : : f_verbose(verbose)
78 1873468 : , f_parser(parser)
79 : {
80 1873468 : as2js::set_message_callback(this);
81 1873468 : fix_counters();
82 1873468 : }
83 :
84 :
85 1873468 : test_callback::~test_callback()
86 : {
87 : // make sure the pointer gets reset!
88 : //
89 1873468 : as2js::set_message_callback(nullptr);
90 1873468 : }
91 :
92 :
93 1873468 : void test_callback::fix_counters()
94 : {
95 1873468 : g_warning_count = as2js::warning_count();
96 1873468 : g_error_count = as2js::error_count();
97 1873468 : }
98 :
99 :
100 : // implementation of the output
101 2573474 : void test_callback::output(as2js::message_level_t message_level, as2js::err_code_t error_code, as2js::position const & pos, std::string const& message)
102 : {
103 : // skip trace messages
104 : //
105 2573474 : if(message_level == as2js::message_level_t::MESSAGE_LEVEL_TRACE)
106 : {
107 0 : return;
108 : }
109 2573474 : ++f_position;
110 :
111 2573474 : if(f_expected.empty())
112 : {
113 0 : std::cerr << "\n*** STILL NECESSARY *** (#" << f_position << ")\n";
114 0 : std::cerr << "filename = " << pos.get_filename() << "\n";
115 0 : std::cerr << "message level = " << static_cast<int>(message_level) << " (" << message_level << ")\n";
116 0 : std::cerr << "msg = " << message << "\n";
117 0 : std::cerr << "page = " << pos.get_page() << "\n";
118 0 : std::cerr << "line = " << pos.get_line() << "\n";
119 0 : std::cerr << "error code = " << static_cast<int>(error_code) << " (" << error_code_to_str(error_code) << ")\n";
120 : }
121 :
122 2573474 : CATCH_REQUIRE(!f_expected.empty());
123 :
124 : // the compiler uses this flag to generate the following warning
125 : //
126 2573474 : if(f_parser)
127 : {
128 : std::cerr << "\n >>> WARNING <<<\n"
129 : " >>> You got an error from the parser. These should not happen here.\n"
130 : " >>> If you need to test something in the parser, move your test to the\n"
131 0 : " >>> tests/parser_data/*.json files instead.\n\n";
132 : }
133 :
134 5146948 : bool const error(!f_expected[0].f_call
135 2573474 : || message_level != f_expected[0].f_message_level
136 2573474 : || error_code != f_expected[0].f_error_code
137 7720422 : || pos.get_filename() != f_expected[0].f_pos.get_filename()
138 5146948 : || pos.get_function() != f_expected[0].f_pos.get_function()
139 2573474 : || pos.get_page() != f_expected[0].f_pos.get_page()
140 2573474 : || pos.get_page_line() != f_expected[0].f_pos.get_page_line()
141 2573474 : || pos.get_paragraph() != f_expected[0].f_pos.get_paragraph()
142 2573474 : || pos.get_line() != f_expected[0].f_pos.get_line()
143 5146948 : || message != f_expected[0].f_message);
144 2573474 : bool const verbose(f_verbose || error);
145 2573474 : if(verbose)
146 : {
147 0 : std::cerr << "\n";
148 0 : if(error)
149 : {
150 0 : std::cerr << "*** FAILED TEST *** (#" << f_position << ")\n";
151 : }
152 : else
153 : {
154 0 : std::cerr << "*** TEST MESSAGE *** (#" << f_position << ")\n";
155 : }
156 0 : std::cerr << "filename = " << pos.get_filename() << " (node) / " << f_expected[0].f_pos.get_filename() << " (JSON)\n";
157 0 : std::cerr << "message level = " << static_cast<int>(message_level) << " (" << message_level
158 0 : << ") / " << static_cast<int>(f_expected[0].f_message_level) << " (" << f_expected[0].f_message_level << ")\n";
159 : std::cerr << "msg = " << message << '\n'
160 0 : << " / " << f_expected[0].f_message << '\n';
161 0 : std::cerr << "page = " << pos.get_page() << " / " << f_expected[0].f_pos.get_page() << '\n';
162 0 : std::cerr << "line = " << pos.get_line() << " / " << f_expected[0].f_pos.get_line() << '\n';
163 0 : std::cerr << "page line = " << pos.get_page_line() << " / " << f_expected[0].f_pos.get_page_line() << '\n';
164 0 : std::cerr << "error code = " << static_cast<int>(error_code) << " (" << error_code_to_str(error_code)
165 0 : << ") / " << static_cast<int>(f_expected[0].f_error_code)
166 0 : << " (" << error_code_to_str(f_expected[0].f_error_code) << ")\n";
167 : }
168 :
169 2573474 : CATCH_REQUIRE(f_expected[0].f_call);
170 2573474 : CATCH_REQUIRE(message_level == f_expected[0].f_message_level);
171 2573474 : CATCH_REQUIRE(error_code == f_expected[0].f_error_code);
172 2573474 : CATCH_REQUIRE(pos.get_filename() == f_expected[0].f_pos.get_filename());
173 2573474 : CATCH_REQUIRE(pos.get_function() == f_expected[0].f_pos.get_function());
174 2573474 : CATCH_REQUIRE(pos.get_page() == f_expected[0].f_pos.get_page());
175 2573474 : CATCH_REQUIRE(pos.get_page_line() == f_expected[0].f_pos.get_page_line());
176 2573474 : CATCH_REQUIRE(pos.get_paragraph() == f_expected[0].f_pos.get_paragraph());
177 2573474 : CATCH_REQUIRE(pos.get_line() == f_expected[0].f_pos.get_line());
178 2573474 : CATCH_REQUIRE(message == f_expected[0].f_message);
179 :
180 2573474 : if(message_level == as2js::message_level_t::MESSAGE_LEVEL_WARNING)
181 : {
182 16398 : ++g_warning_count;
183 16398 : CATCH_REQUIRE(g_warning_count == as2js::warning_count());
184 : }
185 :
186 2573474 : if(message_level == as2js::message_level_t::MESSAGE_LEVEL_FATAL
187 2573474 : || message_level == as2js::message_level_t::MESSAGE_LEVEL_ERROR)
188 : {
189 2548884 : ++g_error_count;
190 : //std::cerr << "error: " << g_error_count << " / " << as2js::error_count() << "\n";
191 2548884 : CATCH_REQUIRE(g_error_count == as2js::error_count());
192 : }
193 :
194 2573474 : f_expected.erase(f_expected.begin());
195 : }
196 :
197 1835442 : void test_callback::got_called()
198 : {
199 1835442 : if(!f_expected.empty())
200 : {
201 0 : std::cerr << "\n*** STILL " << f_expected.size() << " EXPECTED *** (#" << f_position << ")\n";
202 0 : std::cerr << "filename = " << f_expected[0].f_pos.get_filename() << "\n";
203 0 : std::cerr << "message level = " << static_cast<int>(f_expected[0].f_message_level)
204 0 : << " (" << f_expected[0].f_message_level << ")\n";
205 0 : std::cerr << "msg = " << f_expected[0].f_message << "\n";
206 0 : std::cerr << "page = " << f_expected[0].f_pos.get_page() << "\n";
207 0 : std::cerr << "line = " << f_expected[0].f_pos.get_line() << "\n";
208 0 : std::cerr << "error code = " << static_cast<int>(f_expected[0].f_error_code)
209 0 : << " (" << error_code_to_str(f_expected[0].f_error_code) << ")\n";
210 : }
211 1835442 : CATCH_REQUIRE(f_expected.empty());
212 1835442 : }
213 :
214 : std::int32_t test_callback::g_warning_count = 0;
215 : std::int32_t test_callback::g_error_count = 0;
216 :
217 :
218 :
219 :
220 :
221 : // functions to convert error codes to/from strings
222 :
223 : struct err_to_string_t
224 : {
225 : as2js::err_code_t f_code;
226 : char const * f_name;
227 : int f_line;
228 : };
229 :
230 : #define ERROR_NAME(err) { as2js::err_code_t::AS_ERR_##err, TO_STR_sub(err), __LINE__ }
231 :
232 : constexpr err_to_string_t const g_error_table[] =
233 : {
234 : ERROR_NAME(NONE),
235 : ERROR_NAME(ABSTRACT),
236 : ERROR_NAME(BAD_NUMERIC_TYPE),
237 : ERROR_NAME(BAD_PRAGMA),
238 : ERROR_NAME(CANNOT_COMPILE),
239 : ERROR_NAME(CANNOT_MATCH),
240 : ERROR_NAME(CANNOT_OVERLOAD),
241 : ERROR_NAME(CANNOT_OVERWRITE_CONST),
242 : ERROR_NAME(CASE_LABEL),
243 : ERROR_NAME(COLON_EXPECTED),
244 : ERROR_NAME(COMMA_EXPECTED),
245 : ERROR_NAME(CURVLY_BRACKETS_EXPECTED),
246 : ERROR_NAME(DEFAULT_LABEL),
247 : ERROR_NAME(DIVIDE_BY_ZERO),
248 : ERROR_NAME(DUPLICATES),
249 : ERROR_NAME(DYNAMIC),
250 : ERROR_NAME(EXPRESSION_EXPECTED),
251 : ERROR_NAME(FINAL),
252 : ERROR_NAME(IMPROPER_STATEMENT),
253 : ERROR_NAME(INACCESSIBLE_STATEMENT),
254 : ERROR_NAME(INCOMPATIBLE),
255 : ERROR_NAME(INCOMPATIBLE_PRAGMA_ARGUMENT),
256 : ERROR_NAME(INSTALLATION),
257 : ERROR_NAME(INSTANCE_EXPECTED),
258 : ERROR_NAME(INTERNAL_ERROR),
259 : ERROR_NAME(NATIVE),
260 : ERROR_NAME(INVALID_ARRAY_FUNCTION),
261 : ERROR_NAME(INVALID_ATTRIBUTES),
262 : ERROR_NAME(INVALID_CATCH),
263 : ERROR_NAME(INVALID_CLASS),
264 : ERROR_NAME(INVALID_CONDITIONAL),
265 : ERROR_NAME(INVALID_DEFINITION),
266 : ERROR_NAME(INVALID_DO),
267 : ERROR_NAME(INVALID_ENUM),
268 : ERROR_NAME(INVALID_EXPRESSION),
269 : ERROR_NAME(INVALID_FIELD),
270 : ERROR_NAME(INVALID_FIELD_NAME),
271 : ERROR_NAME(INVALID_FRAME),
272 : ERROR_NAME(INVALID_FUNCTION),
273 : ERROR_NAME(INVALID_GOTO),
274 : ERROR_NAME(INVALID_IMPORT),
275 : ERROR_NAME(INVALID_INPUT_STREAM),
276 : ERROR_NAME(INVALID_KEYWORD),
277 : ERROR_NAME(INVALID_LABEL),
278 : ERROR_NAME(INVALID_NAMESPACE),
279 : ERROR_NAME(INVALID_NODE),
280 : ERROR_NAME(INVALID_NUMBER),
281 : ERROR_NAME(INVALID_OPERATOR),
282 : ERROR_NAME(INVALID_PACKAGE_NAME),
283 : ERROR_NAME(INVALID_PARAMETERS),
284 : ERROR_NAME(INVALID_REST),
285 : ERROR_NAME(INVALID_RETURN_TYPE),
286 : ERROR_NAME(INVALID_SCOPE),
287 : ERROR_NAME(INVALID_TEMPLATE),
288 : ERROR_NAME(INVALID_TRY),
289 : ERROR_NAME(INVALID_TYPE),
290 : ERROR_NAME(INVALID_UNICODE_ESCAPE_SEQUENCE),
291 : ERROR_NAME(INVALID_VARIABLE),
292 : ERROR_NAME(IO_ERROR),
293 : ERROR_NAME(LABEL_NOT_FOUND),
294 : ERROR_NAME(LOOPING_REFERENCE),
295 : ERROR_NAME(MISMATCH_FUNC_VAR),
296 : ERROR_NAME(MISSSING_VARIABLE_NAME),
297 : ERROR_NAME(NEED_CONST),
298 : ERROR_NAME(NOT_ALLOWED),
299 : ERROR_NAME(NOT_ALLOWED_IN_STRICT_MODE),
300 : ERROR_NAME(NOT_FOUND),
301 : ERROR_NAME(NOT_SUPPORTED),
302 : ERROR_NAME(OBJECT_MEMBER_DEFINED_TWICE),
303 : ERROR_NAME(PARENTHESIS_EXPECTED),
304 : ERROR_NAME(PRAGMA_FAILED),
305 : ERROR_NAME(SEMICOLON_EXPECTED),
306 : ERROR_NAME(SQUARE_BRACKETS_EXPECTED),
307 : ERROR_NAME(STRING_EXPECTED),
308 : ERROR_NAME(STATIC),
309 : ERROR_NAME(TYPE_NOT_LINKED),
310 : ERROR_NAME(UNKNOWN_ESCAPE_SEQUENCE),
311 : ERROR_NAME(UNKNOWN_OPERATOR),
312 : ERROR_NAME(UNKNOWN_PRAGMA),
313 : ERROR_NAME(UNTERMINATED_STRING),
314 : ERROR_NAME(UNEXPECTED_EOF),
315 : ERROR_NAME(UNEXPECTED_PUNCTUATION),
316 : ERROR_NAME(UNEXPECTED_TOKEN),
317 : ERROR_NAME(UNEXPECTED_DATABASE),
318 : ERROR_NAME(UNEXPECTED_RC)
319 : };
320 : constexpr std::size_t const g_error_table_size = sizeof(g_error_table) / sizeof(g_error_table[0]);
321 :
322 :
323 1458190 : as2js::err_code_t str_to_error_code(std::string const & error_name)
324 : {
325 66609810 : for(size_t idx(0); idx < g_error_table_size; ++idx)
326 : {
327 66609810 : if(error_name == g_error_table[idx].f_name)
328 : {
329 1458190 : return g_error_table[idx].f_code;
330 : }
331 : }
332 0 : std::cerr << "Error name \"" << error_name << "\" not found.\n";
333 0 : CATCH_REQUIRE(!"error name not found, catch_parser.cpp bug");
334 0 : return as2js::err_code_t::AS_ERR_NONE;
335 : }
336 :
337 :
338 0 : char const * error_code_to_str(as2js::err_code_t const error_code)
339 : {
340 : // TODO: the error code should be in order
341 : // 1. verify that the order is indeed correct
342 : // 2. use a binary search instead
343 : //
344 0 : for(std::size_t idx(0); idx < g_error_table_size; ++idx)
345 : {
346 0 : if(error_code == g_error_table[idx].f_code)
347 : {
348 0 : return g_error_table[idx].f_name;
349 : }
350 : }
351 0 : std::cerr << "Error code \"" << static_cast<int>(error_code) << "\" not found.\n";
352 0 : CATCH_REQUIRE(!"error code not found, catch_parser.cpp bug");
353 0 : return "unknown";
354 : }
355 :
356 :
357 :
358 :
359 :
360 :
361 : // Options
362 :
363 : //
364 : // we have two special pragmas that accept 0, 1, 2, or 3
365 : // namely, those are:
366 : //
367 : // . OPTION_EXTENDED_STATEMENTS -- force '{' ... '}' in
368 : // blocks for: if, while, do, for, with...
369 : //
370 : // . OPTION_EXTENDED_OPERATORS -- force ':=' instead of '='
371 : //
372 : // for this reason we support and f_value which is viewed
373 : // as a set of flags
374 : //
375 : named_options const g_options[] =
376 : {
377 : {
378 : as2js::option_t::OPTION_ALLOW_WITH,
379 : "allow_with",
380 : "no_allow_with",
381 : 1
382 : },
383 : {
384 : as2js::option_t::OPTION_COVERAGE,
385 : "coverage",
386 : "no_coverage",
387 : 1
388 : },
389 : {
390 : as2js::option_t::OPTION_DEBUG,
391 : "debug",
392 : "no_debug",
393 : 1
394 : },
395 : {
396 : as2js::option_t::OPTION_EXTENDED_ESCAPE_SEQUENCES,
397 : "extended_escape_sequences",
398 : "no_extended_escape_sequences",
399 : 1
400 : },
401 : {
402 : as2js::option_t::OPTION_EXTENDED_OPERATORS,
403 : "extended_operators",
404 : "no_extended_operators",
405 : 1
406 : },
407 : {
408 : as2js::option_t::OPTION_EXTENDED_OPERATORS,
409 : "extended_operators_safe",
410 : "no_extended_operators_safe",
411 : 2
412 : },
413 : {
414 : as2js::option_t::OPTION_EXTENDED_STATEMENTS,
415 : "extended_statements",
416 : "no_extended_statements",
417 : 1
418 : },
419 : {
420 : as2js::option_t::OPTION_EXTENDED_STATEMENTS,
421 : "extended_statements_safe",
422 : "no_extended_statements_safe",
423 : 2
424 : },
425 : //{ -- this one does not make sense here
426 : // as2js::option_t::OPTION_JSON,
427 : // "json",
428 : // "no_json"
429 : //},
430 : {
431 : as2js::option_t::OPTION_OCTAL,
432 : "octal",
433 : "no_octal",
434 : 1
435 : },
436 : {
437 : as2js::option_t::OPTION_STRICT,
438 : "strict",
439 : "no_strict",
440 : 1
441 : },
442 : {
443 : as2js::option_t::OPTION_TRACE,
444 : "trace",
445 : "no_trace",
446 : 1
447 : },
448 : {
449 : as2js::option_t::OPTION_UNSAFE_MATH,
450 : "unsafe_math",
451 : "no_unsafe_math",
452 : 1
453 : }
454 : };
455 : std::size_t const g_options_size = sizeof(g_options) / sizeof(g_options[0]);
456 :
457 :
458 :
459 :
460 :
461 :
462 : // Flags
463 :
464 : struct flg_to_string_t
465 : {
466 : as2js::flag_t f_flag;
467 : char const * f_name;
468 : int f_line;
469 : };
470 :
471 : #define FLAG_NAME(flg) { as2js::flag_t::NODE_##flg, TO_STR_sub(flg), __LINE__ }
472 :
473 : constexpr flg_to_string_t const g_flag_table[] =
474 : {
475 : FLAG_NAME(CATCH_FLAG_TYPED),
476 : FLAG_NAME(DIRECTIVE_LIST_FLAG_NEW_VARIABLES),
477 : FLAG_NAME(ENUM_FLAG_CLASS),
478 : FLAG_NAME(FOR_FLAG_CONST),
479 : FLAG_NAME(FOR_FLAG_FOREACH),
480 : FLAG_NAME(FOR_FLAG_IN),
481 : FLAG_NAME(FUNCTION_FLAG_GETTER),
482 : FLAG_NAME(FUNCTION_FLAG_SETTER),
483 : FLAG_NAME(FUNCTION_FLAG_OUT),
484 : FLAG_NAME(FUNCTION_FLAG_VOID),
485 : FLAG_NAME(FUNCTION_FLAG_NEVER),
486 : FLAG_NAME(FUNCTION_FLAG_NOPARAMS),
487 : FLAG_NAME(FUNCTION_FLAG_OPERATOR),
488 : FLAG_NAME(IDENTIFIER_FLAG_WITH),
489 : FLAG_NAME(IDENTIFIER_FLAG_TYPED),
490 : FLAG_NAME(IMPORT_FLAG_IMPLEMENTS),
491 : FLAG_NAME(PACKAGE_FLAG_FOUND_LABELS),
492 : FLAG_NAME(PACKAGE_FLAG_REFERENCED),
493 : FLAG_NAME(PARAM_FLAG_CONST),
494 : FLAG_NAME(PARAM_FLAG_IN),
495 : FLAG_NAME(PARAM_FLAG_OUT),
496 : FLAG_NAME(PARAM_FLAG_NAMED),
497 : FLAG_NAME(PARAM_FLAG_REST),
498 : FLAG_NAME(PARAM_FLAG_UNCHECKED),
499 : FLAG_NAME(PARAM_FLAG_UNPROTOTYPED),
500 : FLAG_NAME(PARAM_FLAG_REFERENCED),
501 : FLAG_NAME(PARAM_FLAG_PARAMREF),
502 : FLAG_NAME(PARAM_FLAG_CATCH),
503 : FLAG_NAME(PARAM_MATCH_FLAG_UNPROTOTYPED),
504 : FLAG_NAME(SWITCH_FLAG_DEFAULT),
505 : FLAG_NAME(TYPE_FLAG_MODULO),
506 : FLAG_NAME(VARIABLE_FLAG_CONST),
507 : FLAG_NAME(VARIABLE_FLAG_FINAL),
508 : FLAG_NAME(VARIABLE_FLAG_LOCAL),
509 : FLAG_NAME(VARIABLE_FLAG_MEMBER),
510 : FLAG_NAME(VARIABLE_FLAG_ATTRIBUTES),
511 : FLAG_NAME(VARIABLE_FLAG_ENUM),
512 : FLAG_NAME(VARIABLE_FLAG_COMPILED),
513 : FLAG_NAME(VARIABLE_FLAG_INUSE),
514 : FLAG_NAME(VARIABLE_FLAG_ATTRS),
515 : FLAG_NAME(VARIABLE_FLAG_DEFINED),
516 : FLAG_NAME(VARIABLE_FLAG_DEFINING),
517 : FLAG_NAME(VARIABLE_FLAG_TOADD)
518 : };
519 : constexpr std::size_t const g_flag_table_size = sizeof(g_flag_table) / sizeof(g_flag_table[0]);
520 :
521 :
522 1249280 : as2js::flag_t str_to_flag_code(std::string const & flag_name)
523 : {
524 28192768 : for(size_t idx(0); idx < g_flag_table_size; ++idx)
525 : {
526 28192768 : if(flag_name == g_flag_table[idx].f_name)
527 : {
528 1249280 : return g_flag_table[idx].f_flag;
529 : }
530 : }
531 : //CATCH_REQUIRE(!"flag code not found, catch_parser.cpp bug");
532 0 : CATCH_REQUIRE(flag_name == "unknown flag");
533 0 : return as2js::flag_t::NODE_FLAG_max;
534 : }
535 :
536 :
537 0 : std::string flag_to_str(as2js::flag_t const flg)
538 : {
539 0 : for(size_t idx(0); idx < g_flag_table_size; ++idx)
540 : {
541 0 : if(flg == g_flag_table[idx].f_flag)
542 : {
543 0 : return g_flag_table[idx].f_name;
544 : }
545 : }
546 0 : CATCH_REQUIRE(!"flag code not found, catch_parser.cpp bug");
547 0 : return "";
548 : }
549 :
550 :
551 :
552 :
553 13258341 : void verify_flags(as2js::node::pointer_t node, std::string const & flags_set, bool verbose)
554 : {
555 : // list of flags that have to be set
556 : //
557 13258341 : std::vector<as2js::flag_t> flgs;
558 13258341 : char const * f(flags_set.c_str());
559 13258341 : char const * s(f);
560 : for(;;)
561 : {
562 36802149 : if(*f == ',' || *f == '\0')
563 : {
564 13631077 : if(s == f)
565 : {
566 12381797 : break;
567 : }
568 2498560 : std::string name(s, f - s);
569 : //std::cerr << "Checking " << name << " -> " << static_cast<int>(str_to_flag_code(name)) << "\n";
570 1249280 : flgs.push_back(str_to_flag_code(name));
571 1249280 : if(*f == '\0')
572 : {
573 876544 : break;
574 : }
575 : do // skip commas
576 : {
577 372736 : ++f;
578 : }
579 372736 : while(*f == ',');
580 372736 : s = f;
581 1622016 : }
582 : else
583 : {
584 23171072 : ++f;
585 : }
586 23543808 : }
587 :
588 : // list of flags that must be checked
589 13258341 : std::vector<as2js::flag_t> flgs_to_check;
590 13258341 : switch(node->get_type())
591 : {
592 36864 : case as2js::node_t::NODE_CATCH:
593 36864 : flgs_to_check.push_back(as2js::flag_t::NODE_CATCH_FLAG_TYPED);
594 36864 : break;
595 :
596 1450855 : case as2js::node_t::NODE_DIRECTIVE_LIST:
597 1450855 : flgs_to_check.push_back(as2js::flag_t::NODE_DIRECTIVE_LIST_FLAG_NEW_VARIABLES);
598 1450855 : break;
599 :
600 90112 : case as2js::node_t::NODE_ENUM:
601 90112 : flgs_to_check.push_back(as2js::flag_t::NODE_ENUM_FLAG_CLASS);
602 90112 : break;
603 :
604 53252 : case as2js::node_t::NODE_FOR:
605 53252 : flgs_to_check.push_back(as2js::flag_t::NODE_FOR_FLAG_CONST);
606 53252 : flgs_to_check.push_back(as2js::flag_t::NODE_FOR_FLAG_FOREACH);
607 53252 : flgs_to_check.push_back(as2js::flag_t::NODE_FOR_FLAG_IN);
608 53252 : break;
609 :
610 499712 : case as2js::node_t::NODE_FUNCTION:
611 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_GETTER);
612 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_NEVER);
613 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_NOPARAMS);
614 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_OPERATOR);
615 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_OUT);
616 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_SETTER);
617 499712 : flgs_to_check.push_back(as2js::flag_t::NODE_FUNCTION_FLAG_VOID);
618 499712 : break;
619 :
620 2724219 : case as2js::node_t::NODE_IDENTIFIER:
621 : case as2js::node_t::NODE_VIDENTIFIER:
622 : case as2js::node_t::NODE_STRING:
623 2724219 : flgs_to_check.push_back(as2js::flag_t::NODE_IDENTIFIER_FLAG_WITH);
624 2724219 : flgs_to_check.push_back(as2js::flag_t::NODE_IDENTIFIER_FLAG_TYPED);
625 2724219 : break;
626 :
627 81920 : case as2js::node_t::NODE_IMPORT:
628 81920 : flgs_to_check.push_back(as2js::flag_t::NODE_IMPORT_FLAG_IMPLEMENTS);
629 81920 : break;
630 :
631 65536 : case as2js::node_t::NODE_PACKAGE:
632 65536 : flgs_to_check.push_back(as2js::flag_t::NODE_PACKAGE_FLAG_FOUND_LABELS);
633 65536 : flgs_to_check.push_back(as2js::flag_t::NODE_PACKAGE_FLAG_REFERENCED);
634 65536 : break;
635 :
636 0 : case as2js::node_t::NODE_PARAM_MATCH:
637 0 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_MATCH_FLAG_UNPROTOTYPED);
638 0 : break;
639 :
640 544768 : case as2js::node_t::NODE_PARAM:
641 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_CATCH);
642 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_CONST);
643 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_IN);
644 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_OUT);
645 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_NAMED);
646 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_PARAMREF);
647 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_REFERENCED);
648 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_REST);
649 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_UNCHECKED);
650 544768 : flgs_to_check.push_back(as2js::flag_t::NODE_PARAM_FLAG_UNPROTOTYPED);
651 544768 : break;
652 :
653 40960 : case as2js::node_t::NODE_SWITCH:
654 40960 : flgs_to_check.push_back(as2js::flag_t::NODE_SWITCH_FLAG_DEFAULT);
655 40960 : break;
656 :
657 385024 : case as2js::node_t::NODE_TYPE:
658 385024 : flgs_to_check.push_back(as2js::flag_t::NODE_TYPE_FLAG_MODULO);
659 385024 : break;
660 :
661 405504 : case as2js::node_t::NODE_VARIABLE:
662 : case as2js::node_t::NODE_VAR_ATTRIBUTES:
663 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_CONST);
664 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_FINAL);
665 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_LOCAL);
666 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_MEMBER);
667 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_ATTRIBUTES);
668 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_ENUM);
669 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_COMPILED);
670 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_INUSE);
671 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_ATTRS);
672 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_DEFINED);
673 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_DEFINING);
674 405504 : flgs_to_check.push_back(as2js::flag_t::NODE_VARIABLE_FLAG_TOADD);
675 405504 : break;
676 :
677 6879615 : default:
678 : // no flags supported
679 6879615 : break;
680 :
681 : }
682 :
683 13258341 : CATCH_REQUIRE(flgs.size() <= flgs_to_check.size());
684 :
685 34895054 : for(size_t idx(0); idx < flgs_to_check.size(); ++idx)
686 : {
687 21636713 : as2js::flag_t flg(flgs_to_check[idx]);
688 21636713 : std::vector<as2js::flag_t>::iterator it(std::find(flgs.begin(), flgs.end(), flg));
689 21636713 : if(it == flgs.end())
690 : {
691 : // expected to be unset
692 20387433 : if(verbose && node->get_flag(flg))
693 : {
694 : std::cerr
695 : << "\n*** Comparing flags "
696 0 : << flag_to_str(flg)
697 0 : << " (should not be set):\n"
698 0 : << *node
699 0 : << "\n";
700 : }
701 20387433 : CATCH_REQUIRE(!node->get_flag(flg));
702 : }
703 : else
704 : {
705 : // expected to be set
706 1249280 : flgs.erase(it);
707 1249280 : if(verbose && !node->get_flag(flg))
708 : {
709 : std::cerr
710 : << "\n*** Comparing flags "
711 0 : << flag_to_str(flg)
712 0 : << " (it should be set in this case):\n"
713 0 : << *node
714 0 : << "\n";
715 : }
716 1249280 : CATCH_REQUIRE(node->get_flag(flg));
717 : }
718 : }
719 :
720 13258341 : CATCH_REQUIRE(flgs.empty());
721 26516682 : }
722 :
723 :
724 :
725 :
726 :
727 :
728 : // Attributes
729 :
730 : struct attr_to_string_t
731 : {
732 : as2js::attribute_t f_attribute;
733 : char const * f_name;
734 : int f_line;
735 : };
736 :
737 : #define ATTRIBUTE_NAME(attr) { as2js::attribute_t::NODE_ATTR_##attr, TO_STR_sub(attr), __LINE__ }
738 :
739 : constexpr attr_to_string_t const g_attribute_table[] =
740 : {
741 : ATTRIBUTE_NAME(PUBLIC),
742 : ATTRIBUTE_NAME(PRIVATE),
743 : ATTRIBUTE_NAME(PROTECTED),
744 : ATTRIBUTE_NAME(INTERNAL),
745 : ATTRIBUTE_NAME(TRANSIENT),
746 : ATTRIBUTE_NAME(VOLATILE),
747 : ATTRIBUTE_NAME(STATIC),
748 : ATTRIBUTE_NAME(ABSTRACT),
749 : ATTRIBUTE_NAME(VIRTUAL),
750 : ATTRIBUTE_NAME(ARRAY),
751 : ATTRIBUTE_NAME(REQUIRE_ELSE),
752 : ATTRIBUTE_NAME(ENSURE_THEN),
753 : ATTRIBUTE_NAME(NATIVE),
754 : ATTRIBUTE_NAME(DEPRECATED),
755 : ATTRIBUTE_NAME(UNSAFE),
756 : ATTRIBUTE_NAME(CONSTRUCTOR),
757 : ATTRIBUTE_NAME(FINAL),
758 : ATTRIBUTE_NAME(ENUMERABLE),
759 : ATTRIBUTE_NAME(TRUE),
760 : ATTRIBUTE_NAME(FALSE),
761 : ATTRIBUTE_NAME(UNUSED),
762 : ATTRIBUTE_NAME(DYNAMIC),
763 : ATTRIBUTE_NAME(FOREACH),
764 : ATTRIBUTE_NAME(NOBREAK),
765 : ATTRIBUTE_NAME(AUTOBREAK),
766 : ATTRIBUTE_NAME(DEFINED)
767 : };
768 : constexpr std::size_t const g_attribute_table_size = sizeof(g_attribute_table) / sizeof(g_attribute_table[0]);
769 :
770 :
771 364544 : as2js::attribute_t str_to_attribute_code(std::string const & attr_name)
772 : {
773 8085504 : for(std::size_t idx(0); idx < g_attribute_table_size; ++idx)
774 : {
775 8085504 : if(attr_name == g_attribute_table[idx].f_name)
776 : {
777 364544 : return g_attribute_table[idx].f_attribute;
778 : }
779 : }
780 0 : CATCH_REQUIRE(!"attribute code not found, catch_parser.cpp bug");
781 0 : return as2js::attribute_t::NODE_ATTR_max;
782 : }
783 :
784 :
785 0 : std::string attribute_to_str(as2js::attribute_t const attr)
786 : {
787 0 : for(std::size_t idx(0); idx < g_attribute_table_size; ++idx)
788 : {
789 0 : if(attr == g_attribute_table[idx].f_attribute)
790 : {
791 0 : return g_attribute_table[idx].f_name;
792 : }
793 : }
794 0 : CATCH_REQUIRE(!"attribute code not found, catch_parser.cpp bug");
795 0 : return std::string();
796 : }
797 :
798 :
799 :
800 :
801 13258341 : void verify_attributes(as2js::node::pointer_t n, std::string const & attributes_set, bool verbose)
802 : {
803 : // list of attributes that have to be set
804 : //
805 13258341 : std::vector<as2js::attribute_t> attrs;
806 13258341 : char const * a(attributes_set.c_str());
807 13258341 : char const * s(a);
808 : for(;;)
809 : {
810 15879781 : if(*a == ',' || *a == '\0')
811 : {
812 13368933 : if(s == a)
813 : {
814 13004389 : break;
815 : }
816 729088 : std::string const name(s, a - s);
817 364544 : attrs.push_back(str_to_attribute_code(name));
818 364544 : if(*a == '\0')
819 : {
820 253952 : break;
821 : }
822 : do // skip commas
823 : {
824 110592 : ++a;
825 : }
826 110592 : while(*a == ',');
827 110592 : s = a;
828 475136 : }
829 : else
830 : {
831 2510848 : ++a;
832 : }
833 2621440 : }
834 :
835 : // list of attributes that must be checked
836 13258341 : std::vector<as2js::attribute_t> attrs_to_check;
837 :
838 13258341 : if(n->get_type() != as2js::node_t::NODE_PROGRAM)
839 : {
840 : // except for PROGRAM, all attributes always apply
841 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_PUBLIC);
842 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_PRIVATE);
843 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_PROTECTED);
844 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_INTERNAL);
845 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_TRANSIENT);
846 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_VOLATILE);
847 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_STATIC);
848 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_ABSTRACT);
849 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_VIRTUAL);
850 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_ARRAY);
851 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_REQUIRE_ELSE);
852 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_ENSURE_THEN);
853 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_NATIVE);
854 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_DEPRECATED);
855 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_UNSAFE);
856 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_CONSTRUCTOR);
857 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_FINAL);
858 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_ENUMERABLE);
859 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_TRUE);
860 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_FALSE);
861 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_UNUSED);
862 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_DYNAMIC);
863 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_FOREACH);
864 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_NOBREAK);
865 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_AUTOBREAK);
866 12499735 : attrs_to_check.push_back(as2js::attribute_t::NODE_ATTR_DEFINED);
867 : }
868 :
869 13258341 : CATCH_REQUIRE(attrs.size() <= attrs_to_check.size());
870 :
871 338251451 : for(size_t idx(0); idx < attrs_to_check.size(); ++idx)
872 : {
873 324993110 : as2js::attribute_t attr(attrs_to_check[idx]);
874 324993110 : std::vector<as2js::attribute_t>::iterator it(std::find(attrs.begin(), attrs.end(), attr));
875 324993110 : if(it == attrs.end())
876 : {
877 : // expected to be unset
878 : //
879 324628566 : if(verbose && n->get_attribute(attr))
880 : {
881 : std::cerr
882 : << "*** Comparing attributes "
883 0 : << attribute_to_str(attr)
884 0 : << " (should not be set)\n"
885 0 : << *n
886 0 : << '\n';
887 : }
888 324628566 : CATCH_REQUIRE(!n->get_attribute(attr));
889 : }
890 : else
891 : {
892 : // expected to be set
893 : //
894 364544 : attrs.erase(it);
895 364544 : if(verbose && !n->get_attribute(attr))
896 : {
897 : std::cerr
898 : << "*** Comparing attributes "
899 0 : << attribute_to_str(attr)
900 0 : << " (it should be set in this case)\n"
901 0 : << *n
902 0 : << '\n';
903 : }
904 364544 : CATCH_REQUIRE(n->get_attribute(attr));
905 : }
906 : }
907 :
908 13258341 : CATCH_REQUIRE(attrs.empty());
909 26516682 : }
910 :
911 :
912 :
913 65861625 : void verify_child_node(
914 : std::string const & result_name
915 : , as2js::json::json_value::pointer_t expected
916 : , as2js::json::json_value::object_t const & json_object
917 : , as2js::node::pointer_t node
918 : , as2js::node::pointer_t link_node
919 : , char const * link_name
920 : , bool direct
921 : , bool verbose)
922 : {
923 65861625 : as2js::json::json_value::object_t::const_iterator it_link(json_object.find(link_name));
924 65861625 : if(it_link != json_object.end())
925 : {
926 : // the children value must be an array
927 : //
928 565248 : as2js::json::json_value::array_t const & array(it_link->second->get_array());
929 565248 : std::size_t const max_links(array.size());
930 565248 : if(link_node != nullptr)
931 : {
932 565248 : if(direct)
933 : {
934 86016 : if(verbose && max_links != 1)
935 : {
936 : std::cerr
937 0 : << " Expecting "
938 0 : << max_links
939 : << " "
940 : << link_name
941 0 : << ", we always have 1 in the node (direct)\n";
942 : }
943 86016 : CATCH_REQUIRE(max_links == 1);
944 86016 : as2js::json::json_value::pointer_t link_value(array[0]);
945 86016 : verify_result(result_name, link_value, link_node, verbose, true); // recursive
946 86016 : }
947 : else
948 : {
949 479232 : if(verbose && max_links != link_node->get_children_size())
950 : {
951 : std::cerr
952 0 : << " Expecting "
953 0 : << max_links
954 : << " "
955 : << link_name
956 0 : << ", we have "
957 0 : << link_node->get_children_size()
958 0 : << " in the node\n";
959 : }
960 479232 : CATCH_REQUIRE(max_links == link_node->get_children_size());
961 1056768 : for(std::size_t idx(0); idx < max_links; ++idx)
962 : {
963 577536 : as2js::json::json_value::pointer_t link_value(array[idx]);
964 577536 : verify_result(result_name, link_value, link_node->get_child(idx), verbose, false); // recursive
965 577536 : }
966 : }
967 : }
968 : else
969 : {
970 0 : if(verbose && max_links != 0)
971 : {
972 : std::cerr
973 : << " "
974 : << result_name
975 0 : << ": Expecting "
976 0 : << max_links
977 : << ' '
978 : << link_name
979 : << ", we have no "
980 : << link_name
981 0 : << " at all in the node\n";
982 : }
983 0 : CATCH_REQUIRE(max_links == 0);
984 : }
985 : }
986 : else
987 : {
988 : // no children defined in the JSON, no children expected in the node
989 : //
990 65296377 : if(verbose
991 2199552 : && link_node != nullptr
992 67495929 : && link_node->get_children_size() != 0)
993 : {
994 : std::cerr
995 : << " Expecting no \""
996 : << link_name
997 0 : << "\" list, we have "
998 0 : << link_node->get_children_size()
999 : << " "
1000 : << link_name
1001 0 : << " in the node:\n"
1002 0 : << *node
1003 0 : << "JSON position: "
1004 0 : << expected->get_position()
1005 0 : << "\nComparing against link node:\n"
1006 0 : << *link_node;
1007 : }
1008 65296377 : bool const valid_link(link_node == nullptr || link_node->get_children_size() == 0);
1009 65296377 : CATCH_REQUIRE(valid_link);
1010 : }
1011 65861625 : }
1012 :
1013 :
1014 13258341 : void verify_result(
1015 : std::string const & result_name
1016 : , as2js::json::json_value::pointer_t expected
1017 : , as2js::node::pointer_t node
1018 : , bool verbose
1019 : , bool ignore_children)
1020 : {
1021 26516682 : std::string const node_type_string("node type");
1022 26516682 : std::string const children_string("children");
1023 : //std::string link_strings[static_cast<int>(as2js::link_t::LINK_max)];
1024 : //link_strings[0].from_utf8("link instance");
1025 : //link_strings[1].from_utf8("link type");
1026 : //link_strings[2].from_utf8("link attributes");
1027 : //link_strings[3].from_utf8("link goto exit");
1028 : //link_strings[4].from_utf8("link goto enter");
1029 26516682 : std::string const label_string("label");
1030 26516682 : std::string const flags_string("flags");;
1031 26516682 : std::string const attributes_string("attributes");
1032 26516682 : std::string const integer_string("integer");
1033 26516682 : std::string const float_string("float");
1034 :
1035 13258341 : CATCH_REQUIRE(expected->get_type() == as2js::json::json_value::type_t::JSON_TYPE_OBJECT);
1036 13258341 : as2js::json::json_value::object_t const & child_object(expected->get_object());
1037 :
1038 13258341 : as2js::json::json_value::object_t::const_iterator it_node_type(child_object.find(node_type_string));
1039 13258341 : if(it_node_type == child_object.end())
1040 : {
1041 : std::cerr
1042 0 : << "\nerror: \"node type\" is mandatory in your JSON:\n"
1043 0 : << *expected
1044 0 : << "\n";
1045 0 : exit(1);
1046 : }
1047 13258341 : as2js::json::json_value::pointer_t node_type_value(it_node_type->second);
1048 13258341 : if(verbose && node->get_type_name() != node_type_value->get_string())
1049 : {
1050 : std::cerr
1051 : << "*** Comparing "
1052 : << node->get_type_name()
1053 : << " (node) vs "
1054 0 : << node_type_value->get_string()
1055 0 : << " (JSON) -- pos: "
1056 0 : << expected->get_position()
1057 0 : << " -- Node:\n"
1058 0 : << *node
1059 0 : << "JSON:\n"
1060 0 : << *node_type_value;
1061 0 : switch(node->get_type())
1062 : {
1063 0 : case as2js::node_t::NODE_IDENTIFIER:
1064 0 : std::cerr << " \"" << node->get_string() << "\"";
1065 0 : break;
1066 :
1067 0 : default:
1068 : // no details for this node type
1069 0 : break;
1070 :
1071 : }
1072 0 : std::cerr << "\n";
1073 : }
1074 13258341 : CATCH_REQUIRE(node->get_type_name() == node_type_value->get_string());
1075 :
1076 13258341 : as2js::json::json_value::object_t::const_iterator it_label(child_object.find(label_string));
1077 13258341 : if(it_label != child_object.end())
1078 : {
1079 : // we expect a string in this object
1080 5075325 : if(verbose && node->get_string() != it_label->second->get_string())
1081 : {
1082 0 : std::cerr << " Expecting string \"" << it_label->second->get_string() << "\", node has \"" << node->get_string() << "\"\n";
1083 : }
1084 5075325 : CATCH_REQUIRE(node->get_string() == it_label->second->get_string());
1085 : //std::cerr << " -- labels are a match! [" << node->get_string() << "]\n";
1086 : }
1087 : else
1088 : {
1089 : // the node cannot have a string otherwise, so we expect a throw
1090 8183016 : CATCH_REQUIRE_THROWS_MATCHES(
1091 : node->get_string()
1092 : , as2js::internal_error
1093 : , Catch::Matchers::ExceptionMessage(
1094 : "internal_error: get_string() called with non-string node type: \""
1095 : + std::string(node->get_type_name())
1096 : + "\"."));
1097 : }
1098 :
1099 13258341 : as2js::json::json_value::object_t::const_iterator it_flags(child_object.find(flags_string));
1100 13258341 : if(it_flags != child_object.end())
1101 : {
1102 : // the tester declared as set of flags that are expected to be set
1103 : //
1104 876544 : verify_flags(node, it_flags->second->get_string(), verbose);
1105 : }
1106 : else
1107 : {
1108 : // all flags must be unset
1109 : //
1110 12381797 : verify_flags(node, "", verbose);
1111 : }
1112 :
1113 : // WARNING: these attributes are what we call IMMEDIATE ATTRIBUTES in case
1114 : // of the parser because the parser also makes use of a
1115 : // LINK_ATTRIBUTES which represents a list of attributes
1116 13258341 : as2js::json::json_value::object_t::const_iterator it_attributes(child_object.find(attributes_string));
1117 13258341 : if(it_attributes != child_object.end())
1118 : {
1119 : // the tester declared as set of attributes that are expected to be set
1120 253952 : verify_attributes(node, it_attributes->second->get_string(), verbose);
1121 : }
1122 : else
1123 : {
1124 : // all attributes must be unset
1125 13004389 : verify_attributes(node, "", verbose);
1126 : }
1127 :
1128 13258341 : as2js::json::json_value::object_t::const_iterator it_integer(child_object.find(integer_string));
1129 13258341 : if(it_integer != child_object.end())
1130 : {
1131 : // we expect an integer in this object
1132 782619 : if(node->get_integer().get() != it_integer->second->get_integer().get())
1133 : {
1134 0 : std::cerr << " Expecting " << it_integer->second->get_integer().get() << ", got " << node->get_integer().get() << " in the node\n";
1135 : }
1136 782619 : CATCH_REQUIRE(node->get_integer().get() == it_integer->second->get_integer().get());
1137 : }
1138 : else
1139 : {
1140 : // the node cannot have an integer otherwise, so we expect a throw
1141 : //
1142 12475722 : CATCH_REQUIRE_THROWS_MATCHES(
1143 : node->get_integer()
1144 : , as2js::internal_error
1145 : , Catch::Matchers::ExceptionMessage(
1146 : "internal_error: get_integer() called with a non-integer node type."));
1147 : }
1148 :
1149 13258341 : as2js::json::json_value::object_t::const_iterator it_float(child_object.find(float_string));
1150 13258341 : if(it_float != child_object.end())
1151 : {
1152 : // if we expect a NaN we have to compare specifically
1153 : // because (NaN == NaN) always returns false
1154 : //
1155 65927 : if(it_float->second->get_floating_point().is_nan())
1156 : {
1157 74 : CATCH_REQUIRE(node->get_floating_point().is_nan());
1158 : }
1159 65853 : else if(it_float->second->get_floating_point().is_positive_infinity())
1160 : {
1161 89 : CATCH_REQUIRE(node->get_floating_point().is_positive_infinity());
1162 : }
1163 65764 : else if(it_float->second->get_floating_point().is_negative_infinity())
1164 : {
1165 1 : CATCH_REQUIRE(node->get_floating_point().is_negative_infinity());
1166 : }
1167 : else
1168 : {
1169 : // we expect a floating point number in this object
1170 65763 : if(node->get_floating_point().get() - it_float->second->get_floating_point().get() > 0.0001)
1171 : {
1172 0 : std::cerr << " Expecting " << it_float->second->get_floating_point().get() << ", got " << node->get_floating_point().get() << " in the node\n";
1173 : }
1174 65763 : CATCH_REQUIRE(node->get_floating_point().get() - it_float->second->get_floating_point().get() <= 0.0001);
1175 :
1176 : // further, if the float is zero, it may be +0.0 or -0.0
1177 : #pragma GCC diagnostic push
1178 : #pragma GCC diagnostic ignored "-Wfloat-equal"
1179 65763 : if(it_float->second->get_floating_point().get() == 0.0)
1180 : {
1181 11 : CATCH_REQUIRE(std::signbit(node->get_floating_point().get()) == std::signbit(it_float->second->get_floating_point().get()));
1182 : }
1183 : #pragma GCC diagnostic pop
1184 : }
1185 : }
1186 : else
1187 : {
1188 : // the node cannot have a floating point otherwise, so we expect a throw
1189 13192414 : CATCH_REQUIRE_THROWS_MATCHES(
1190 : node->get_floating_point()
1191 : , as2js::internal_error
1192 : , Catch::Matchers::ExceptionMessage(
1193 : "internal_error: get_floating_point() called with a non-floating point node type."));
1194 : }
1195 :
1196 : // COMPILER / OPTIMIZER SPECIFIC?
1197 : // certain links asks us to ignore the links and children because
1198 : // we do not want to duplicate the whole type classes a hundred times...
1199 13258341 : if(!ignore_children)
1200 : {
1201 : //std::cerr << "Node is [" << *node << "]\n";
1202 :
1203 : // verify the links
1204 13172325 : verify_child_node(result_name, expected, child_object, node, node->get_instance(), "instance", true, verbose);
1205 13172325 : verify_child_node(result_name, expected, child_object, node, node->get_type_node(), "type node", true, verbose);
1206 13172325 : verify_child_node(result_name, expected, child_object, node, node->get_attribute_node(), "attribute node", false, verbose);
1207 13172325 : verify_child_node(result_name, expected, child_object, node, node->get_goto_exit(), "goto exit", false, verbose);
1208 13172325 : verify_child_node(result_name, expected, child_object, node, node->get_goto_enter(), "goto enter", false, verbose);
1209 :
1210 : // // List of links are tested just like children, only the list starts somewhere else
1211 : // for(int link_idx(0); link_idx < static_cast<int>(as2js::Node::link_t::LINK_max); ++link_idx)
1212 : // {
1213 : // as2js::String link_name;
1214 : // switch(static_cast<as2js::Node::link_t>(link_idx))
1215 : // {
1216 : // case as2js::Node::link_t::LINK_INSTANCE:
1217 : // link_name = "instance";
1218 : // break;
1219 : //
1220 : // case as2js::Node::link_t::LINK_TYPE:
1221 : // link_name = "type";
1222 : // break;
1223 : //
1224 : // case as2js::Node::link_t::LINK_ATTRIBUTES:
1225 : // link_name = "attributes";
1226 : // break;
1227 : //
1228 : // case as2js::Node::link_t::LINK_GOTO_EXIT:
1229 : // link_name = "goto-exit";
1230 : // break;
1231 : //
1232 : // case as2js::Node::link_t::LINK_GOTO_ENTER:
1233 : // link_name = "goto-enter";
1234 : // break;
1235 : //
1236 : // case as2js::Node::link_t::LINK_max:
1237 : // CATCH_REQUIRE(!"LINK_max reached when getting the link type");
1238 : // break;
1239 : //
1240 : // }
1241 : // bool direct(false);
1242 : // as2js::Node::pointer_t link_node(node->get_link(static_cast<as2js::Node::link_t>(link_idx)));
1243 : // if(link_node)
1244 : // {
1245 : // // make sure root node is of the right type
1246 : // // Why did I write this that way? The types from the time
1247 : // // we created the tree in the parser are still around...
1248 : // switch(static_cast<as2js::Node::link_t>(link_idx))
1249 : // {
1250 : // case as2js::Node::link_t::LINK_INSTANCE:
1251 : // direct = true;
1252 : ////std::cerr << "Instance [" << *link_node << "]\n";
1253 : // //CATCH_REQUIRE(!"compiler does not use LINK_INSTANCE");
1254 : // break;
1255 : //
1256 : // case as2js::Node::link_t::LINK_TYPE:
1257 : // direct = true;
1258 : ////std::cerr << "Type [" << *link_node << "]\n";
1259 : // //CATCH_REQUIRE(!"compiler does not use LINK_TYPE");
1260 : // break;
1261 : //
1262 : // case as2js::Node::link_t::LINK_ATTRIBUTES:
1263 : // direct = false;
1264 : // CATCH_REQUIRE(link_node->get_type() == as2js::Node::node_t::NODE_ATTRIBUTES);
1265 : // break;
1266 : //
1267 : // case as2js::Node::link_t::LINK_GOTO_EXIT:
1268 : // CATCH_REQUIRE(!"compiler does not use LINK_GOTO_EXIT");
1269 : // break;
1270 : //
1271 : // case as2js::Node::link_t::LINK_GOTO_ENTER:
1272 : // CATCH_REQUIRE(!"compiler does not use LINK_GOTO_ENTER");
1273 : // break;
1274 : //
1275 : // case as2js::Node::link_t::LINK_max:
1276 : // CATCH_REQUIRE(!"LINK_max reached when testing the link_node type");
1277 : // break;
1278 : //
1279 : // }
1280 : // }
1281 : // as2js::JSON::JSONValue::object_t::const_iterator it_link(child_object.find(link_strings[link_idx]));
1282 : // if(it_link != child_object.end())
1283 : // {
1284 : // // the children value must be an array
1285 : // as2js::JSON::JSONValue::array_t const& array(it_link->second->get_array());
1286 : // size_t const max_links(array.size());
1287 : // if(link_node)
1288 : // {
1289 : // if(direct)
1290 : // {
1291 : // if(verbose && max_links != 1)
1292 : // {
1293 : // std::cerr << " Expecting " << max_links << " " << link_name << ", we always have 1 in the node (direct)\n";
1294 : // }
1295 : // CATCH_REQUIRE(max_links == 1);
1296 : // as2js::JSON::JSONValue::pointer_t link_value(array[0]);
1297 : // verify_result(result_name, link_value, link_node, verbose, true); // recursive
1298 : // }
1299 : // else
1300 : // {
1301 : // if(verbose && max_links != link_node->get_children_size())
1302 : // {
1303 : // std::cerr << " Expecting " << max_links << " " << link_name << ", we have " << link_node->get_children_size() << " in the node\n";
1304 : // }
1305 : // CATCH_REQUIRE(max_links == link_node->get_children_size());
1306 : // for(size_t idx(0); idx < max_links; ++idx)
1307 : // {
1308 : // as2js::JSON::JSONValue::pointer_t link_value(array[idx]);
1309 : // verify_result(result_name, link_value, link_node->get_child(idx), verbose, false); // recursive
1310 : // }
1311 : // }
1312 : // }
1313 : // else
1314 : // {
1315 : // if(verbose && max_links != 0)
1316 : // {
1317 : // std::cerr << " Expecting " << max_links << " " << link_name << ", we have no " << link_name << " at all in the node\n";
1318 : // }
1319 : // CATCH_REQUIRE(max_links == 0);
1320 : // }
1321 : // }
1322 : // else
1323 : // {
1324 : // // no children defined in the JSON, no children expected in the node
1325 : // if(verbose && link_node && link_node->get_children_size() != 0)
1326 : // {
1327 : // std::cerr << " Expecting no " << link_name << " list, we have " << link_node->get_children_size() << " " << link_name << " in the node\n";
1328 : // }
1329 : // CATCH_REQUIRE(!link_node || link_node->get_children_size() == 0);
1330 : // }
1331 : // }
1332 :
1333 13172325 : as2js::json::json_value::object_t::const_iterator it_children(child_object.find(children_string));
1334 13172325 : if(it_children != child_object.end())
1335 : {
1336 : // the children value must be an array
1337 7805230 : as2js::json::json_value::array_t const& array(it_children->second->get_array());
1338 7805230 : size_t const max_children(array.size());
1339 7805230 : if(verbose && max_children != node->get_children_size())
1340 : {
1341 : std::cerr
1342 0 : << " Expecting "
1343 0 : << max_children
1344 0 : << " children, we have "
1345 0 : << node->get_children_size()
1346 0 : << " in the node:\n"
1347 0 : << *node;
1348 : }
1349 7805230 : CATCH_REQUIRE(max_children == node->get_children_size());
1350 19641413 : for(size_t idx(0); idx < max_children; ++idx)
1351 : {
1352 11836183 : as2js::json::json_value::pointer_t children_value(array[idx]);
1353 11836183 : verify_result(result_name, children_value, node->get_child(idx), verbose, ignore_children); // recursive
1354 11836183 : }
1355 : }
1356 : else
1357 : {
1358 : // no children defined in the JSON, no children expected in the node
1359 5367095 : if(verbose && node->get_children_size() != 0)
1360 : {
1361 : std::cerr
1362 0 : << " Expecting no children, we have "
1363 0 : << node->get_children_size()
1364 0 : << " in the node:\n"
1365 0 : << *node
1366 0 : << "\n";
1367 : }
1368 5367095 : CATCH_REQUIRE(node->get_children_size() == 0);
1369 : }
1370 : }
1371 26516682 : }
1372 :
1373 :
1374 : // Parser verification
1375 684032 : void verify_parser_result(
1376 : std::string const & result_name
1377 : , as2js::json::json_value::pointer_t expected
1378 : , as2js::node::pointer_t node
1379 : , bool verbose
1380 : , bool ignore_children)
1381 : {
1382 684032 : verify_result(result_name, expected, node, verbose, ignore_children);
1383 :
1384 : // the parser does not define these so we expect them all to be null pointers
1385 684032 : CATCH_REQUIRE(node->get_instance() == nullptr);
1386 684032 : CATCH_REQUIRE(node->get_type_node() == nullptr);
1387 684032 : CATCH_REQUIRE(node->get_goto_exit() == nullptr);
1388 684032 : CATCH_REQUIRE(node->get_goto_enter() == nullptr);
1389 :
1390 684032 : as2js::json::json_value::object_t const & child_object(expected->get_object());
1391 684032 : as2js::json::json_value::object_t::const_iterator it_attribute(child_object.find("attribute node"));
1392 684032 : as2js::node::pointer_t attribute_node(node->get_attribute_node());
1393 684032 : if(attribute_node != nullptr)
1394 : {
1395 : // if it exists it must be a NODE_ATTRIBUTES type
1396 0 : CATCH_REQUIRE(attribute_node->get_type() == as2js::node_t::NODE_ATTRIBUTES);
1397 :
1398 0 : if(it_attribute == child_object.end())
1399 : {
1400 0 : std::size_t const count(attribute_node->get_children_size());
1401 0 : if(verbose && count > 0)
1402 : {
1403 : std::cerr
1404 0 : << " Expecting no \"attributes\", we have "
1405 0 : << count
1406 0 : << " in the node\n";
1407 : }
1408 0 : CATCH_REQUIRE(count == 0);
1409 : }
1410 : else
1411 : {
1412 : // the children value must be an array
1413 0 : as2js::json::json_value::array_t const & array(it_attribute->second->get_array());
1414 0 : size_t const max_links(array.size());
1415 0 : if(verbose && max_links != attribute_node->get_children_size())
1416 : {
1417 : std::cerr
1418 0 : << " Expecting "
1419 0 : << max_links
1420 0 : << " instance, we have "
1421 0 : << attribute_node->get_children_size()
1422 0 : << " in the node\n";
1423 : }
1424 0 : CATCH_REQUIRE(max_links == attribute_node->get_children_size());
1425 0 : for(size_t idx(0); idx < max_links; ++idx)
1426 : {
1427 0 : as2js::json::json_value::pointer_t attribute_value(array[idx]);
1428 0 : verify_result(result_name, attribute_value, attribute_node->get_child(idx), verbose, false); // recursive
1429 0 : }
1430 : }
1431 : }
1432 : else
1433 : {
1434 : // no attributes in the node, no children expected in the JSON
1435 684032 : if(verbose && it_attribute != child_object.end())
1436 : {
1437 0 : size_t const count(it_attribute->second->get_array().size());
1438 0 : std::cerr << " Expecting " << count << " \"attributes\", we have none in the node\n";
1439 : }
1440 684032 : CATCH_REQUIRE(it_attribute == child_object.end());
1441 : }
1442 1368064 : }
1443 :
1444 :
1445 :
1446 : } // namespace SNAP_CATCH2_NAMESPACE
1447 :
1448 :
1449 2 : Catch::Clara::Parser add_command_line_options(Catch::Clara::Parser const & cli)
1450 : {
1451 : return cli
1452 6 : | Catch::Clara::Opt(SNAP_CATCH2_NAMESPACE::g_as2js_compiler, "as2js")
1453 4 : ["--as2js"]
1454 4 : ("path to the as2js compiler.")
1455 8 : | Catch::Clara::Opt(SNAP_CATCH2_NAMESPACE::g_run_destructive)
1456 4 : ["--destructive"]
1457 4 : ("also run the various destructive/problematic tests that can run on their own but probably not along others (if not specified, skip those tests).")
1458 4 : | Catch::Clara::Opt(SNAP_CATCH2_NAMESPACE::g_save_parser_tests)
1459 4 : ["--save-parser-tests"]
1460 12 : ("save the JSON used to test the parser.");
1461 : }
1462 :
1463 :
1464 1 : int init_test(Catch::Session & session)
1465 : {
1466 1 : snapdev::NOT_USED(session);
1467 :
1468 : // in our snapcpp environment, the default working directory for our
1469 : // tests is the source directory (${CMAKE_SOURCE_DIR}); the as2js tests
1470 : // want to create folders and files inside the current working directory
1471 : // so instead we'd like to be in the temporary directory so change that
1472 : // now at the start
1473 : //
1474 1 : std::string tmp_dir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1475 1 : if(tmp_dir.empty())
1476 : {
1477 : // there is a default set to:
1478 : // /tmp/<project-name>
1479 : // so this should never happen
1480 : //
1481 0 : std::cerr << "error: a temporary directory must be specified.\n";
1482 0 : return 1;
1483 : }
1484 :
1485 1 : int const r(chdir(tmp_dir.c_str()));
1486 1 : if(r != 0)
1487 : {
1488 : std::cerr << "error: could not change working directory to \""
1489 : << tmp_dir
1490 0 : << "\"; the directory must exist.\n";
1491 0 : return 1;
1492 : }
1493 1 : char * cwd(get_current_dir_name());
1494 1 : if(cwd == nullptr)
1495 : {
1496 0 : std::cerr << "error: could not retrieve the current working directory.\n";
1497 0 : return 1;
1498 : }
1499 1 : SNAP_CATCH2_NAMESPACE::g_tmp_dir() = cwd;
1500 1 : free(cwd);
1501 :
1502 : // update this path because otherwise the $HOME variable is going to be
1503 : // wrong (i.e. a relative path from within said relative path is not
1504 : // likely to work properly)
1505 : //
1506 1 : tmp_dir = SNAP_CATCH2_NAMESPACE::g_tmp_dir();
1507 :
1508 : // the snapcatch2 ensures an empty tmp directory so this should just
1509 : // never happen ever...
1510 : //
1511 1 : struct stat st;
1512 1 : if(stat("debian", &st) == 0)
1513 : {
1514 : std::cerr << "error: unexpected \"debian\" directory in the temporary directory;"
1515 0 : " you cannot safely specify the source directory as the temporary directory.\n";
1516 0 : return 1;
1517 : }
1518 1 : if(stat("as2js/CMakeLists.txt", &st) == 0)
1519 : {
1520 : std::cerr << "error: unexpected \"as2js/CMakeLists.txt\" file in the temporary directory;"
1521 0 : " you cannot safely specify the source directory as the temporary directory.\n";
1522 0 : return 1;
1523 : }
1524 :
1525 : // move HOME to a sub-directory inside the temporary directory so that
1526 : // way it is safe (we can change files there without the risk of
1527 : // destroying some of the developer's files)
1528 : //
1529 1 : if(snapdev::mkdir_p("home") != 0)
1530 : {
1531 : std::cerr
1532 : << "error: could not create a \"home\" directory in the temporary directory: \""
1533 : << tmp_dir
1534 0 : << "\".\n";
1535 0 : return 1;
1536 : }
1537 1 : std::string const home(tmp_dir + "/home");
1538 1 : setenv("HOME", home.c_str(), 1);
1539 :
1540 : // some other "modules" that require some initialization
1541 : //
1542 1 : if(SNAP_CATCH2_NAMESPACE::catch_rc_init() != 0)
1543 : {
1544 0 : return 1;
1545 : }
1546 1 : if(SNAP_CATCH2_NAMESPACE::catch_db_init() != 0)
1547 : {
1548 0 : return 1;
1549 : }
1550 1 : if(SNAP_CATCH2_NAMESPACE::catch_compiler_init() != 0)
1551 : {
1552 0 : return 1;
1553 : }
1554 :
1555 1 : return 0;
1556 1 : }
1557 :
1558 :
1559 1 : void cleanup_test()
1560 : {
1561 1 : SNAP_CATCH2_NAMESPACE::catch_compiler_cleanup();
1562 1 : }
1563 :
1564 :
1565 2 : int main(int argc, char * argv[])
1566 : {
1567 2 : return SNAP_CATCH2_NAMESPACE::snap_catch2_main(
1568 : "as2js"
1569 : , AS2JS_VERSION_STRING
1570 : , argc
1571 : , argv
1572 2 : , []() { libexcept::set_collect_stack(libexcept::collect_stack_t::COLLECT_STACK_NO); }
1573 : , &add_command_line_options
1574 : , &init_test
1575 : , &cleanup_test
1576 2 : );
1577 : }
1578 :
1579 :
1580 : // vim: ts=4 sw=4 et
|