LCOV - code coverage report
Current view: top level - tools - as2js.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 577 13.3 %
Date: 2023-07-29 22:00:24 Functions: 7 16 43.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2005-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             : /** \file
      20             :  * \brief This file is the actual as2js compiler/transpiler.
      21             :  *
      22             :  * The project includes a library which does 99% of the work. This is
      23             :  * the implementation of the as2js command line tool that handles
      24             :  * command line options, initializes the necessary objects to compile
      25             :  * .asj files in one of:
      26             :  *
      27             :  * \li a node tree (mainly for debug)
      28             :  * \li binary code (directly Intel/AMD instruction in binary--no specific
      29             :  *     format but it uses the Linux ABI)
      30             :  * \li assembly language (64 bit Intel/AMD)
      31             :  * \li JavaScript (this was the point at first)
      32             :  * \li C++ (create C++ classes .cpp/.h files)
      33             :  *
      34             :  * The tree is very useful for me to debug the lexer, parser, and compiler
      35             :  * work before even trying to transform said tree to something else.
      36             :  *
      37             :  * The binary code is used in our other libraries so that way we do not need
      38             :  * to have any other compiler and/or assembler installed on your server. This
      39             :  * tool and library are enough for you to create a binary file that our
      40             :  * other tools (again using this library) can use to run complex expressions
      41             :  * directly in binary.
      42             :  */
      43             : 
      44             : // self
      45             : //
      46             : #include    "tools/license.h"
      47             : 
      48             : 
      49             : 
      50             : // as2js lib
      51             : //
      52             : #include    <as2js/archive.h>
      53             : #include    <as2js/binary.h>
      54             : #include    <as2js/compiler.h>
      55             : #include    <as2js/exception.h>
      56             : #include    <as2js/message.h>
      57             : #include    <as2js/parser.h>
      58             : #include    <as2js/version.h>
      59             : 
      60             : 
      61             : // snapdev
      62             : //
      63             : #include    <snapdev/pathinfo.h>
      64             : #include    <snapdev/string_replace_many.h>
      65             : #include    <snapdev/to_lower.h>
      66             : 
      67             : 
      68             : // C++
      69             : //
      70             : #include    <cstring>
      71             : #include    <iomanip>
      72             : #include    <set>
      73             : 
      74             : 
      75             : // last include
      76             : //
      77             : #include    <snapdev/poison.h>
      78             : 
      79             : 
      80             : 
      81             : 
      82             : 
      83             : 
      84             : /** \brief Private implementations of the as2js compiler, the actual tool.
      85             :  *
      86             :  * This namespace is used to hide all the tool private functions to
      87             :  * avoid any conflicts.
      88             :  */
      89             : namespace
      90             : {
      91             : 
      92             : 
      93             : 
      94             : enum class command_t
      95             : {
      96             :     COMMAND_UNDEFINED,
      97             : 
      98             :     COMMAND_ASSEMBLY,
      99             :     COMMAND_BINARY,
     100             :     COMMAND_BINARY_VERSION,
     101             :     COMMAND_COMPILER_TREE,
     102             :     COMMAND_CPP,
     103             :     COMMAND_CREATE_ARCHIVE,
     104             :     COMMAND_DATA_SECTION,
     105             :     COMMAND_END_SECTION,
     106             :     COMMAND_EXECUTE,
     107             :     COMMAND_EXTRACT_ARCHIVE,
     108             :     COMMAND_IS_BINARY,
     109             :     COMMAND_JAVASCRIPT,
     110             :     COMMAND_LIST_ARCHIVE,
     111             :     COMMAND_PARSER_TREE,
     112             :     COMMAND_TEXT_SECTION,
     113             :     COMMAND_VARIABLES,
     114             : };
     115             : 
     116             : 
     117             : class as2js_compiler
     118             : {
     119             : public:
     120             :     typedef std::shared_ptr<as2js_compiler>         pointer_t;
     121             : 
     122             :     int                         parse_command_line_options(int argc, char *argv[]);
     123             :     int                         run();
     124             : 
     125             : private:
     126             :     void                        license();
     127             :     void                        usage();
     128             :     void                        version();
     129             :     void                        set_output(command_t output);
     130             :     void                        set_option(
     131             :                                       as2js::option_t option
     132             :                                     , int argc
     133             :                                     , char * argv[]
     134             :                                     , int & i);
     135             :     int                         output_error_count();
     136             :     void                        compile();
     137             :     void                        generate_binary();
     138             :     void                        binary_utils();
     139             :     void                        list_external_variables(
     140             :                                       std::ifstream & in
     141             :                                     , as2js::binary_header & header);
     142             :     void                        create_archive();
     143             :     void                        list_archive();
     144             :     void                        execute();
     145             : 
     146             :     typedef std::map<std::string, std::string>  variable_t;
     147             : 
     148             :     int                         f_error_count = 0;
     149             :     std::string                 f_progname = std::string();
     150             :     std::vector<std::string>    f_filenames = std::vector<std::string>();
     151             :     std::string                 f_save_to_file = std::string();
     152             :     std::string                 f_output = std::string();
     153             :     //std::string                 f_archive_path = std::string();
     154             :     variable_t                  f_variables = variable_t();
     155             :     command_t                   f_command = command_t::COMMAND_UNDEFINED;
     156             :     as2js::options::pointer_t   f_options = std::make_shared<as2js::options>();
     157             :     std::set<as2js::option_t>   f_option_defined = std::set<as2js::option_t>();
     158             :     as2js::node::pointer_t      f_root = as2js::node::pointer_t();
     159             :     bool                        f_ignore_unknown_variables = false;
     160             :     bool                        f_show_all_results = false;
     161             :     bool                        f_three_underscores_to_space = false;
     162             : };
     163             : 
     164             : 
     165          25 : int as2js_compiler::parse_command_line_options(int argc, char *argv[])
     166             : {
     167          25 :     f_progname = snapdev::pathinfo::basename(std::string(argv[0]));
     168             : 
     169         100 :     for(int i(1); i < argc; ++i)
     170             :     {
     171          75 :         if(argv[i][0] == '-'
     172          50 :         && argv[i][1] != '\0')
     173             :         {
     174          50 :             if(argv[i][1] == '-')
     175             :             {
     176           0 :                 if(strcmp(argv[i] + 2, "help") == 0)
     177             :                 {
     178           0 :                     usage();
     179           0 :                     return 1;
     180             :                 }
     181           0 :                 if(strcmp(argv[i] + 2, "license") == 0)
     182             :                 {
     183           0 :                     license();
     184           0 :                     return 1;
     185             :                 }
     186           0 :                 if(strcmp(argv[i] + 2, "version") == 0)
     187             :                 {
     188           0 :                     version();
     189           0 :                     return 1;
     190             :                 }
     191             : 
     192           0 :                 if(strcmp(argv[i] + 2, "log-level") == 0)
     193             :                 {
     194           0 :                     ++i;
     195           0 :                     if(i >= argc)
     196             :                     {
     197           0 :                         ++f_error_count;
     198             :                         std::cerr
     199           0 :                             << "error: the \"--log-level\" option expects one option, the level as a number or its name.\n";
     200             :                     }
     201             :                     else
     202             :                     {
     203           0 :                         as2js::message_level_t const level(as2js::string_to_message_level(argv[i]));
     204           0 :                         if(level != as2js::MESSAGE_LEVEL_INVALID)
     205             :                         {
     206           0 :                             set_message_level(level);
     207             :                         }
     208             :                         else
     209             :                         {
     210           0 :                             ++f_error_count;
     211             :                             std::cerr
     212             :                                 << "error: unknown log level \""
     213           0 :                                 << argv[i]
     214           0 :                                 << "\".\n"; // TODO: add a command to list available levels
     215             :                         }
     216             :                     }
     217             :                 }
     218           0 :                 else if(strcmp(argv[i] + 2, "save-after-execute") == 0)
     219             :                 {
     220           0 :                     ++i;
     221           0 :                     if(i >= argc)
     222             :                     {
     223           0 :                         ++f_error_count;
     224             :                         std::cerr
     225           0 :                             << "error: the \"--save-after-execute\" option expects a filename.\n";
     226             :                     }
     227             :                     else
     228             :                     {
     229           0 :                         f_save_to_file = argv[i];
     230             :                     }
     231             :                 }
     232           0 :                 else if(strcmp(argv[i] + 2, "binary") == 0)
     233             :                 {
     234           0 :                     set_output(command_t::COMMAND_BINARY);
     235             :                 }
     236           0 :                 else if(strcmp(argv[i] + 2, "binary-version") == 0)
     237             :                 {
     238           0 :                     set_output(command_t::COMMAND_BINARY_VERSION);
     239             :                 }
     240           0 :                 else if(strcmp(argv[i] + 2, "create-archive") == 0)
     241             :                 {
     242           0 :                     set_output(command_t::COMMAND_CREATE_ARCHIVE);
     243             :                 }
     244           0 :                 else if(strcmp(argv[i] + 2, "data-section") == 0)
     245             :                 {
     246           0 :                     set_output(command_t::COMMAND_DATA_SECTION);
     247             :                 }
     248           0 :                 else if(strcmp(argv[i] + 2, "end-section") == 0)
     249             :                 {
     250           0 :                     set_output(command_t::COMMAND_END_SECTION);
     251             :                 }
     252           0 :                 else if(strcmp(argv[i] + 2, "execute") == 0)
     253             :                 {
     254           0 :                     set_output(command_t::COMMAND_EXECUTE);
     255             :                 }
     256           0 :                 else if(strcmp(argv[i] + 2, "extract-archive") == 0)
     257             :                 {
     258           0 :                     set_output(command_t::COMMAND_EXTRACT_ARCHIVE);
     259             :                 }
     260           0 :                 else if(strcmp(argv[i] + 2, "is-binary") == 0)
     261             :                 {
     262           0 :                     set_output(command_t::COMMAND_IS_BINARY);
     263             :                 }
     264           0 :                 else if(strcmp(argv[i] + 2, "list-archive") == 0)
     265             :                 {
     266           0 :                     set_output(command_t::COMMAND_LIST_ARCHIVE);
     267             :                 }
     268           0 :                 else if(strcmp(argv[i] + 2, "parser-tree") == 0)
     269             :                 {
     270           0 :                     set_output(command_t::COMMAND_PARSER_TREE);
     271             :                 }
     272           0 :                 else if(strcmp(argv[i] + 2, "text-section") == 0)
     273             :                 {
     274           0 :                     set_output(command_t::COMMAND_TEXT_SECTION);
     275             :                 }
     276           0 :                 else if(strcmp(argv[i] + 2, "compiler-tree") == 0)
     277             :                 {
     278           0 :                     set_output(command_t::COMMAND_COMPILER_TREE);
     279             :                 }
     280           0 :                 else if(strcmp(argv[i] + 2, "variables") == 0)
     281             :                 {
     282           0 :                     set_output(command_t::COMMAND_VARIABLES);
     283             :                 }
     284           0 :                 else if(strcmp(argv[i] + 2, "allow-with") == 0)
     285             :                 {
     286           0 :                     set_option(as2js::option_t::OPTION_ALLOW_WITH, argc, argv, i);
     287             :                 }
     288           0 :                 else if(strcmp(argv[i] + 2, "coverage") == 0)
     289             :                 {
     290           0 :                     set_option(as2js::option_t::OPTION_COVERAGE, argc, argv, i);
     291             :                 }
     292           0 :                 else if(strcmp(argv[i] + 2, "debug") == 0)
     293             :                 {
     294           0 :                     set_option(as2js::option_t::OPTION_DEBUG, argc, argv, i);
     295             :                 }
     296           0 :                 else if(strcmp(argv[i] + 2, "extended-escape-sequences") == 0)
     297             :                 {
     298           0 :                     set_option(as2js::option_t::OPTION_EXTENDED_ESCAPE_SEQUENCES, argc, argv, i);
     299             :                 }
     300           0 :                 else if(strcmp(argv[i] + 2, "extended-escape-operators") == 0)
     301             :                 {
     302           0 :                     set_option(as2js::option_t::OPTION_EXTENDED_OPERATORS, argc, argv, i);
     303             :                 }
     304           0 :                 else if(strcmp(argv[i] + 2, "extended-escape-statements") == 0)
     305             :                 {
     306           0 :                     set_option(as2js::option_t::OPTION_EXTENDED_STATEMENTS, argc, argv, i);
     307             :                 }
     308           0 :                 else if(strcmp(argv[i] + 2, "json") == 0)
     309             :                 {
     310           0 :                     set_option(as2js::option_t::OPTION_JSON, argc, argv, i);
     311             :                 }
     312           0 :                 else if(strcmp(argv[i] + 2, "octal") == 0)
     313             :                 {
     314           0 :                     set_option(as2js::option_t::OPTION_OCTAL, argc, argv, i);
     315             :                 }
     316           0 :                 else if(strcmp(argv[i] + 2, "strict") == 0)
     317             :                 {
     318           0 :                     set_option(as2js::option_t::OPTION_STRICT, argc, argv, i);
     319             :                 }
     320           0 :                 else if(strcmp(argv[i] + 2, "trace") == 0)
     321             :                 {
     322           0 :                     set_option(as2js::option_t::OPTION_TRACE, argc, argv, i);
     323             :                 }
     324           0 :                 else if(strcmp(argv[i] + 2, "unsafe-math") == 0)
     325             :                 {
     326           0 :                     set_option(as2js::option_t::OPTION_UNSAFE_MATH, argc, argv, i);
     327             :                 }
     328           0 :                 else if(strcmp(argv[i] + 2, "ignore-unknown-variables") == 0)
     329             :                 {
     330           0 :                     f_ignore_unknown_variables = true;
     331             :                 }
     332           0 :                 else if(strcmp(argv[i] + 2, "error-on-missing-variables") == 0)
     333             :                 {
     334           0 :                     f_ignore_unknown_variables = false;
     335             :                 }
     336           0 :                 else if(strcmp(argv[i] + 2, "show-all-results") == 0)
     337             :                 {
     338           0 :                     f_show_all_results = true;
     339             :                 }
     340           0 :                 else if(strcmp(argv[i] + 2, "hide-all-results") == 0)
     341             :                 {
     342           0 :                     f_show_all_results = false;
     343             :                 }
     344           0 :                 else if(strcmp(argv[i] + 2, "three-underscores-to-space") == 0)
     345             :                 {
     346           0 :                     f_three_underscores_to_space = false;
     347             :                 }
     348             :                 else
     349             :                 {
     350           0 :                     ++f_error_count;
     351             :                     std::cerr
     352             :                         << "error: unknown command line option \""
     353           0 :                         << argv[i]
     354           0 :                         << "\".\n";
     355             :                 }
     356             :             }
     357             :             else
     358             :             {
     359          50 :                 std::size_t const max(strlen(argv[i]));
     360         100 :                 for(std::size_t j(1); j < max; ++j)
     361             :                 {
     362          50 :                     switch(argv[i][j])
     363             :                     {
     364          25 :                     case 'b':
     365          25 :                         set_output(command_t::COMMAND_BINARY);
     366          25 :                         break;
     367             : 
     368           0 :                     case 'h':
     369           0 :                         usage();
     370           0 :                         return 1;
     371             : 
     372             :                     //case 'L': -- replaced by "extern functions" table
     373             :                     //    if(!f_archive_path.empty())
     374             :                     //    {
     375             :                     //        ++f_error_count;
     376             :                     //        std::cerr
     377             :                     //            << "error: command line option \"-L\" cannot be used more than once.\n";
     378             :                     //    }
     379             :                     //    ++j;
     380             :                     //    if(j >= max)
     381             :                     //    {
     382             :                     //        ++i;
     383             :                     //        if(i >= argc)
     384             :                     //        {
     385             :                     //            ++f_error_count;
     386             :                     //            std::cerr
     387             :                     //                << "error: command line option \"-L\" is expected to be followed by one path.\n";
     388             :                     //        }
     389             :                     //        f_archive_path = argv[i];
     390             :                     //    }
     391             :                     //    else
     392             :                     //    {
     393             :                     //        f_archive_path = argv[i] + j;
     394             :                     //    }
     395             :                     //    break;
     396             : 
     397          25 :                     case 'o':
     398          25 :                         if(!f_output.empty())
     399             :                         {
     400           0 :                             ++f_error_count;
     401             :                             std::cerr
     402           0 :                                 << "error: command line option \"-o\" cannot be used more than once.\n";
     403             :                         }
     404          25 :                         ++j;
     405          25 :                         if(j >= max)
     406             :                         {
     407          25 :                             ++i;
     408          25 :                             if(i >= argc)
     409             :                             {
     410           0 :                                 ++f_error_count;
     411             :                                 std::cerr
     412           0 :                                     << "error: command line option \"-o\" is expected to be followed by one filename.\n";
     413             :                             }
     414          25 :                             f_output = argv[i];
     415             :                         }
     416             :                         else
     417             :                         {
     418           0 :                             f_output = argv[i] + j;
     419             :                         }
     420          25 :                         break;
     421             : 
     422           0 :                     case 't':
     423           0 :                         set_output(command_t::COMMAND_PARSER_TREE);
     424           0 :                         break;
     425             : 
     426           0 :                     case 'T':
     427           0 :                         set_output(command_t::COMMAND_COMPILER_TREE);
     428           0 :                         break;
     429             : 
     430           0 :                     case 'V':
     431           0 :                         version();
     432           0 :                         return 1;
     433             : 
     434           0 :                     default:
     435           0 :                         ++f_error_count;
     436             :                         std::cerr
     437             :                             << "error: unknown command line option \"-"
     438           0 :                             << argv[i][j]
     439           0 :                             << "\".\n";
     440           0 :                         break;
     441             : 
     442             :                     }
     443             :                 }
     444             :             }
     445          50 :         }
     446             :         else
     447             :         {
     448          25 :             char const * equal(strchr(argv[i], '='));
     449          25 :             if(equal == nullptr)
     450             :             {
     451          25 :                 f_filenames.push_back(argv[i]);
     452             :             }
     453           0 :             else if(equal - argv[i] == 0)
     454             :             {
     455           0 :                 ++f_error_count;
     456             :                 std::cerr
     457             :                     << "error: variable name missing in \""
     458           0 :                     << argv[i]
     459           0 :                     << "\".\n";
     460             :             }
     461             :             else
     462             :             {
     463           0 :                 std::string const name(argv[i], equal - argv[i]);
     464           0 :                 std::string const value(equal + 1);
     465           0 :                 f_variables[name] = value;
     466           0 :             }
     467             :         }
     468             :     }
     469             : 
     470          25 :     if(f_command == command_t::COMMAND_UNDEFINED)
     471             :     {
     472             :         // this is what one wants by default (transliteration from
     473             :         // Alex Script to JavaScript)
     474             :         //
     475           0 :         f_command = command_t::COMMAND_JAVASCRIPT;
     476             :     }
     477             : 
     478          25 :     return output_error_count();
     479             : }
     480             : 
     481             : 
     482          50 : int as2js_compiler::output_error_count()
     483             : {
     484          50 :     if(f_error_count != 0)
     485             :     {
     486             :         std::cerr
     487           0 :             << "error: found "
     488             :             << f_error_count 
     489             :             << " error"
     490           0 :             << (f_error_count == 1 ? "" : "s")
     491           0 :             << " in the command line options.\n";
     492           0 :         return 1;
     493             :     }
     494             : 
     495          50 :     return 0;
     496             : }
     497             : 
     498             : 
     499           0 : void as2js_compiler::license()
     500             : {
     501           0 :     std::cout << as2js_tools::license;
     502           0 : }
     503             : 
     504             : 
     505           0 : void as2js_compiler::usage()
     506             : {
     507             :     std::cout
     508           0 :         << "Usage: " << f_progname << " [-opts] <filename>.ajs | <var>=<value> ...\n"
     509             :            "where -opts is one or more of:\n"
     510             :            "Commands (one of):\n"
     511             :            "  -b | --binary          generate a binary file.\n"
     512             :            "       --binary-version  output version of the binary file.\n"
     513             :            "       --data-section    position where the data section starts.\n"
     514             :            "       --end-section     position where the end section starts.\n"
     515             :            "       --error-on-missing-variables\n"
     516             :            "                         variables defined on the command must exist.\n"
     517             :            "       --execute         execute the specified compiled script.\n"
     518             :            "  -h | --help            print out this help screen.\n"
     519             :            "       --hide-all-results\n"
     520             :            "                         do not print the external values before exiting.\n"
     521             :            "       --ignore-unknown-variables\n"
     522             :            "                         variables defined on the command that do not exist\n"
     523             :            "                         can be ignored if not defined in the script.\n"
     524             :            "       --is-binary       check whether a file is a binary file.\n"
     525             :            "       --license         print compiler's license.\n"
     526             :            "  -t | --parser-tree     output the tree of nodes.\n"
     527             :            "       --show-all-results\n"
     528             :            "                         print all the external values before exiting.\n"
     529             :            "       --text-section    position where the text section starts.\n"
     530             :            "  -T | --compiler-tree   output the tree of nodes.\n"
     531             :            "       --variables       list external variables.\n"
     532             :            "  -V | --version         print version of the compiler.\n"
     533             : 
     534             :            "\n"
     535             :            "Options:\n"
     536           0 :            "  -L <path>              path to archive libraries.\n"
     537             :     ;
     538           0 : }
     539             : 
     540             : 
     541           0 : void as2js_compiler::version()
     542             : {
     543             :     std::cout
     544           0 :         << f_progname << " v" << AS2JS_VERSION_STRING << std::endl
     545           0 :         << "libas2js v" << as2js::get_version_string() << std::endl;
     546           0 : }
     547             : 
     548             : 
     549          25 : void as2js_compiler::set_output(command_t command)
     550             : {
     551          25 :     if(f_command != command_t::COMMAND_UNDEFINED)
     552             :     {
     553           0 :         ++f_error_count;
     554           0 :         std::cerr << "error: output type already set. Try only one of --binary, --tree, --is-binary, etc.\n";
     555           0 :         return;
     556             :     }
     557             : 
     558          25 :     f_command = command;
     559             : }
     560             : 
     561             : 
     562           0 : void as2js_compiler::set_option(as2js::option_t option, int argc, char * argv[], int & i)
     563             : {
     564             :     // prevent duplication which will help people understand why something
     565             :     // would possibly not work
     566             :     {
     567           0 :         auto const unique(f_option_defined.insert(option));
     568           0 :         if(!unique.second)
     569             :         {
     570           0 :             ++f_error_count;
     571             :             std::cerr
     572             :                 << "error: option \""
     573           0 :                 << argv[i]
     574           0 :                 << "\" was specified more than once.\n";
     575           0 :             return;
     576             :         }
     577             :     }
     578             : 
     579           0 :     as2js::option_value_t value(0);
     580           0 :     if(i + 1 < argc)
     581             :     {
     582           0 :         char * v(argv[i + 1]);
     583           0 :         if(strcmp(v, "true") == 0)
     584             :         {
     585           0 :             value = 1;
     586           0 :             ++i;
     587             :         }
     588           0 :         else if(strcmp(v, "false") == 0)
     589             :         {
     590           0 :             value = 0;
     591           0 :             ++i;
     592             :         }
     593           0 :         else if(as2js::is_integer(v, true))
     594             :         {
     595           0 :             value = as2js::to_integer(v);
     596           0 :             ++i;
     597             :         }
     598           0 :         else if(as2js::is_floating_point(v))
     599             :         {
     600           0 :             value = as2js::to_floating_point(v);
     601           0 :             ++i;
     602             :         }
     603             :     }
     604           0 :     f_options->set_option(option, value);
     605             : }
     606             : 
     607             : 
     608          25 : int as2js_compiler::run()
     609             : {
     610          25 :     switch(f_command)
     611             :     {
     612           0 :     case command_t::COMMAND_BINARY_VERSION:
     613             :     case command_t::COMMAND_IS_BINARY:
     614             :     case command_t::COMMAND_TEXT_SECTION:
     615             :     case command_t::COMMAND_DATA_SECTION:
     616             :     case command_t::COMMAND_END_SECTION:
     617             :     case command_t::COMMAND_VARIABLES:
     618           0 :         binary_utils();
     619           0 :         break;
     620             : 
     621           0 :     case command_t::COMMAND_CREATE_ARCHIVE:
     622           0 :         create_archive();
     623           0 :         break;
     624             : 
     625           0 :     case command_t::COMMAND_LIST_ARCHIVE:
     626             :     case command_t::COMMAND_EXTRACT_ARCHIVE:
     627           0 :         list_archive();
     628           0 :         break;
     629             : 
     630           0 :     case command_t::COMMAND_EXECUTE:
     631           0 :         execute();
     632           0 :         break;
     633             : 
     634          25 :     case command_t::COMMAND_PARSER_TREE:
     635             :     case command_t::COMMAND_COMPILER_TREE:
     636             :     case command_t::COMMAND_BINARY:
     637             :     case command_t::COMMAND_ASSEMBLY:
     638             :     case command_t::COMMAND_JAVASCRIPT:
     639             :     case command_t::COMMAND_CPP:
     640          25 :         compile();
     641          25 :         break;
     642             : 
     643           0 :     case command_t::COMMAND_UNDEFINED:
     644           0 :         throw as2js::internal_error("found the \"undefined\" command when we should replace it with the default \"javascript\"?");
     645             : 
     646             :     }
     647             : 
     648          25 :     return output_error_count();
     649             : }
     650             : 
     651             : 
     652          25 : void as2js_compiler::compile()
     653             : {
     654          25 :     if(f_filenames.empty())
     655             :     {
     656           0 :         ++f_error_count;
     657           0 :         std::cerr << "error: an input filename is required.\n";
     658           0 :         return;
     659             :     }
     660             : 
     661          25 :     if(f_output.empty())
     662             :     {
     663           0 :         f_output = "a.out";
     664             :     }
     665             : 
     666             :     // we are compiling a user script so mark it as such
     667             :     //
     668          25 :     f_options->set_option(as2js::option_t::OPTION_USER_SCRIPT, 1);
     669             : 
     670             :     // TODO: I'm pretty sure that the following loop would require me to
     671             :     //       load all the _programs_ (user defined files) as children of a
     672             :     //       NODE_ROOT as NODE_PROGRAM and then compile all the NODE_PROGRAM
     673             :     //       nodes at once with one call to the compile() function
     674             :     //
     675          50 :     for(auto const & filename : f_filenames)
     676             :     {
     677          25 :         as2js::reset_errors();
     678             : 
     679             :         // open file
     680             :         //
     681          25 :         as2js::base_stream::pointer_t input;
     682          25 :         if(filename == "-")
     683             :         {
     684           0 :             input = std::make_shared<as2js::cin_stream>();
     685           0 :             input->get_position().set_filename("-");
     686             :         }
     687             :         else
     688             :         {
     689          25 :             as2js::input_stream<std::ifstream>::pointer_t in(std::make_shared<as2js::input_stream<std::ifstream>>());
     690          25 :             in->get_position().set_filename(filename);
     691          25 :             in->open(filename);
     692          25 :             if(!in->is_open())
     693             :             {
     694           0 :                 ++f_error_count;
     695             :                 std::cerr
     696             :                     << "error: could not open file \""
     697             :                     << filename
     698           0 :                     << "\".\n";
     699           0 :                 continue;
     700             :             }
     701          25 :             input = in;
     702          25 :         }
     703             : 
     704             :         // parse the source
     705             :         //
     706          25 :         as2js::parser::pointer_t parser(std::make_shared<as2js::parser>(input, f_options));
     707          25 :         f_root = parser->parse();
     708          25 :         if(as2js::error_count() != 0)
     709             :         {
     710           0 :             ++f_error_count;
     711             :             std::cerr
     712             :                 << "error: parsing of input file \""
     713             :                 << filename
     714           0 :                 << "\" failed.\n";
     715           0 :             continue;
     716             :         }
     717             : 
     718          25 :         if(f_command == command_t::COMMAND_PARSER_TREE)
     719             :         {
     720             :             // user wants to see the parser tree, show that and try next file
     721             :             //
     722           0 :             std::cout << *f_root << "\n";
     723           0 :             continue;
     724             :         }
     725             : 
     726             :         // run the compiler
     727             :         //
     728          50 :         as2js::compiler compiler(f_options);
     729          25 :         if(compiler.compile(f_root) != 0)
     730             :         {
     731             :             // there were errors, skip
     732             :             //
     733           0 :             ++f_error_count;
     734             :             std::cerr
     735             :                 << "error: parsing of input file \""
     736             :                 << filename
     737           0 :                 << "\" failed.\n";
     738           0 :             continue;
     739             :         }
     740             : 
     741          25 :         switch(f_command)
     742             :         {
     743           0 :         case command_t::COMMAND_COMPILER_TREE:
     744           0 :             std::cout << *f_root << "\n";
     745           0 :             break;
     746             : 
     747          25 :         case command_t::COMMAND_BINARY:
     748          25 :             generate_binary();
     749          25 :             break;
     750             : 
     751           0 :         case command_t::COMMAND_ASSEMBLY:
     752             :         case command_t::COMMAND_JAVASCRIPT:
     753             :         case command_t::COMMAND_CPP:
     754           0 :             ++f_error_count;
     755             :             std::cerr
     756           0 :                 << "error: output command not yet implemented.\n";
     757           0 :             break;
     758             : 
     759           0 :         case command_t::COMMAND_BINARY_VERSION:
     760             :         case command_t::COMMAND_CREATE_ARCHIVE:
     761             :         case command_t::COMMAND_IS_BINARY:
     762             :         case command_t::COMMAND_DATA_SECTION:
     763             :         case command_t::COMMAND_END_SECTION:
     764             :         case command_t::COMMAND_EXECUTE:
     765             :         case command_t::COMMAND_EXTRACT_ARCHIVE:
     766             :         case command_t::COMMAND_LIST_ARCHIVE:
     767             :         case command_t::COMMAND_PARSER_TREE:
     768             :         case command_t::COMMAND_TEXT_SECTION:
     769             :         case command_t::COMMAND_UNDEFINED:
     770             :         case command_t::COMMAND_VARIABLES:
     771             :             throw as2js::internal_error("these cases were checked earlier and cannot happen here."); // LCOV_EXCL_LINE
     772             : 
     773             :         }
     774          25 :     }
     775             : }
     776             : 
     777             : 
     778          25 : void as2js_compiler::generate_binary()
     779             : {
     780             :     // TODO: add support for '-' (i.e. stdout)
     781             :     //
     782          25 :     as2js::output_stream<std::ofstream>::pointer_t output(std::make_shared<as2js::output_stream<std::ofstream>>());
     783          25 :     output->open(f_output);
     784          25 :     if(!output->is_open())
     785             :     {
     786           0 :         ++f_error_count;
     787             :         std::cerr
     788             :             << "error: could not open output file \""
     789           0 :             << f_output
     790           0 :             << "\".\n";
     791           0 :         return;
     792             :     }
     793          25 :     as2js::binary_assembler::pointer_t binary(
     794             :             std::make_shared<as2js::binary_assembler>(
     795             :                       output
     796          25 :                     , f_options));
     797          25 :     int const errcnt(binary->output(f_root));
     798          25 :     if(errcnt != 0)
     799             :     {
     800           0 :         ++f_error_count;
     801             :         std::cerr
     802           0 :             << "error: "
     803             :             << errcnt
     804           0 :             << " errors occured while transforming the tree to binary.\n";
     805             :     }
     806          25 : }
     807             : 
     808             : 
     809           0 : void as2js_compiler::binary_utils()
     810             : {
     811           0 :     if(!f_output.empty())
     812             :     {
     813           0 :         ++f_error_count;
     814             :         std::cerr
     815             :             << "as2js:error: no output file ("
     816           0 :             << f_output
     817           0 :             << ") is supported with this command.\n";
     818           0 :         return;
     819             :     }
     820             : 
     821           0 :     if(f_filenames.empty())
     822             :     {
     823           0 :         f_filenames.push_back("a.out");
     824             :     }
     825             : 
     826             :     // open input file
     827             :     //
     828           0 :     std::ifstream in;
     829           0 :     in.open(f_filenames[0]);
     830           0 :     if(!in.is_open())
     831             :     {
     832           0 :         ++f_error_count;
     833             :         std::cerr
     834             :             << "as2js:error: could not open \""
     835           0 :             << f_filenames[0]
     836           0 :             << "\" as input binary file.\n";
     837           0 :         return;
     838             :     }
     839             : 
     840             :     // read the header
     841             :     //
     842           0 :     as2js::binary_header header;
     843           0 :     in.read(reinterpret_cast<char *>(&header), sizeof(header));
     844             : 
     845           0 :     if(header.f_magic[0] != as2js::BINARY_MAGIC_B0
     846           0 :     || header.f_magic[1] != as2js::BINARY_MAGIC_B1
     847           0 :     || header.f_magic[2] != as2js::BINARY_MAGIC_B2
     848           0 :     || header.f_magic[3] != as2js::BINARY_MAGIC_B3)
     849             :     {
     850           0 :         ++f_error_count;
     851             :         std::cerr << "as2js:error: file \""
     852           0 :             << f_filenames[0]
     853           0 :             << "\" does not look like an as2js binary file (invalid magic).\n";
     854           0 :         return;
     855             :     }
     856             : 
     857           0 :     switch(f_command)
     858             :     {
     859           0 :     case command_t::COMMAND_BINARY_VERSION:
     860             :         std::cout
     861           0 :             << static_cast<int>(header.f_version_major)
     862           0 :             << '.'
     863           0 :             << static_cast<int>(header.f_version_minor)
     864           0 :             << '\n';
     865           0 :         return;
     866             : 
     867           0 :     case command_t::COMMAND_IS_BINARY:
     868             :         // that was sufficient for this command, return now
     869           0 :         return;
     870             : 
     871           0 :     case command_t::COMMAND_TEXT_SECTION:
     872           0 :         std::cout << header.f_start << '\n';
     873           0 :         return;
     874             : 
     875           0 :     case command_t::COMMAND_DATA_SECTION:
     876           0 :         std::cout << header.f_variables << '\n';
     877           0 :         return;
     878             : 
     879           0 :     case command_t::COMMAND_END_SECTION:
     880             :         // this is the file size minus 4
     881             :         //
     882           0 :         in.seekg(0, std::ios_base::end);
     883           0 :         std::cout << in.tellg() - 4L << '\n';
     884           0 :         return;
     885             : 
     886           0 :     case command_t::COMMAND_VARIABLES:
     887           0 :         list_external_variables(in, header);
     888           0 :         return;
     889             : 
     890           0 :     default:
     891             :         throw as2js::internal_error("these cases were checked earlier and cannot happen here"); // LCOV_EXCL_LINE
     892             : 
     893             :     }
     894           0 : }
     895             : 
     896             : 
     897           0 : void as2js_compiler::list_external_variables(std::ifstream & in, as2js::binary_header & header)
     898             : {
     899             :     // list external variables
     900             :     //
     901           0 :     in.seekg(header.f_variables, std::ios_base::beg);
     902           0 :     as2js::binary_variable::vector_t variables(header.f_variable_count);
     903           0 :     in.read(reinterpret_cast<char *>(variables.data()), sizeof(as2js::binary_variable) * header.f_variable_count);
     904           0 :     for(std::uint16_t idx(0); idx < header.f_variable_count; ++idx)
     905             :     {
     906           0 :         std::string name;
     907           0 :         if(variables[idx].f_name_size < sizeof(variables[idx].f_name))
     908             :         {
     909           0 :             name = std::string(
     910           0 :                       reinterpret_cast<char const *>(&variables[idx].f_name)
     911           0 :                     , variables[idx].f_name_size);
     912             :         }
     913             :         else
     914             :         {
     915           0 :             in.seekg(variables[idx].f_name, std::ios_base::beg);
     916           0 :             name = std::string(variables[idx].f_name_size, ' ');
     917           0 :             in.read(name.data(), variables[idx].f_name_size);
     918             :         }
     919           0 :         if(idx == 0)
     920             :         {
     921           0 :             std::cout << "var ";
     922             :         }
     923             :         else
     924             :         {
     925           0 :             std::cout << ",\n    ";
     926             :         }
     927             : #if 0
     928             : // show the offset of where the variable data is defined
     929             : // (for easy verification purposes, instead of having to read the binary)
     930             : //
     931             : std::cout
     932             :     << " /* offset: "
     933             :     << (variables[idx].f_data_size > sizeof(variables[idx].f_data)
     934             :             ? variables[idx].f_data
     935             :             : header.f_variables
     936             :                 + idx * sizeof(as2js::binary_variable)
     937             :                 + offsetof(as2js::binary_variable, f_data))
     938             :     << " */ ";
     939             : #endif
     940           0 :         std::cout << name;
     941           0 :         switch(variables[idx].f_type)
     942             :         {
     943           0 :         case as2js::variable_type_t::VARIABLE_TYPE_BOOLEAN:
     944           0 :             std::cout << ": Boolean";
     945           0 :             if(variables[idx].f_data != 0)
     946             :             {
     947           0 :                 std::cerr << " := true";
     948             :             }
     949           0 :             break;
     950             : 
     951           0 :         case as2js::variable_type_t::VARIABLE_TYPE_INTEGER:
     952           0 :             std::cout << ": Integer";
     953           0 :             if(variables[idx].f_data != 0)
     954             :             {
     955           0 :                 std::cerr << " := " << variables[idx].f_data;
     956             :             }
     957           0 :             break;
     958             : 
     959           0 :         case as2js::variable_type_t::VARIABLE_TYPE_FLOATING_POINT:
     960           0 :             std::cout << ": Double";
     961           0 :             if(variables[idx].f_data != 0)
     962             :             {
     963           0 :                 std::uint64_t const * ptr(&variables[idx].f_data);
     964           0 :                 std::cerr << " := " << *reinterpret_cast<double const *>(ptr);
     965             :             }
     966           0 :             break;
     967             : 
     968           0 :         case as2js::variable_type_t::VARIABLE_TYPE_STRING:
     969           0 :             std::cout << ": String";
     970           0 :             if(variables[idx].f_data_size > 0)
     971             :             {
     972           0 :                 std::string value;
     973           0 :                 if(variables[idx].f_data_size < sizeof(variables[idx].f_data))
     974             :                 {
     975           0 :                     value = std::string(
     976           0 :                               reinterpret_cast<char const *>(&variables[idx].f_data)
     977           0 :                             , variables[idx].f_data_size);
     978             :                 }
     979             :                 else
     980             :                 {
     981           0 :                     in.seekg(variables[idx].f_data, std::ios_base::beg);
     982           0 :                     value = std::string(variables[idx].f_data_size, ' ');
     983           0 :                     in.read(value.data(), variables[idx].f_data_size);
     984             :                 }
     985           0 :                 std::cout << " = " << value;
     986           0 :             }
     987           0 :             break;
     988             : 
     989             :         //case as2js::variable_type_t::VARIABLE_TYPE_UNKNOWN:
     990           0 :         default:
     991           0 :             std::cout << " /* unknown type */ ";
     992           0 :             break;
     993             : 
     994             :         }
     995           0 :     }
     996           0 :     std::cout << ";\n";
     997           0 : }
     998             : 
     999             : 
    1000           0 : void as2js_compiler::create_archive()
    1001             : {
    1002           0 :     as2js::archive ar;
    1003           0 :     if(!ar.create(f_filenames))
    1004             :     {
    1005           0 :         ++f_error_count;
    1006             :         std::cerr
    1007           0 :             << "error: could not create archive file.\n";
    1008           0 :         return;
    1009             :     }
    1010             : 
    1011           0 :     as2js::output_stream<std::ofstream>::pointer_t output(std::make_shared<as2js::output_stream<std::ofstream>>());
    1012           0 :     output->open(f_output);
    1013           0 :     if(!output->is_open())
    1014             :     {
    1015           0 :         ++f_error_count;
    1016             :         std::cerr
    1017             :             << "error: could not open archive file \""
    1018           0 :             << f_output
    1019           0 :             << "\" to save run-time functions.\n";
    1020           0 :         return;
    1021             :     }
    1022             : 
    1023           0 :     if(!ar.save(output))
    1024             :     {
    1025           0 :         ++f_error_count;
    1026             :         std::cerr
    1027             :             << "error: could not save archive file \""
    1028           0 :             << f_output
    1029           0 :             << "\".\n";
    1030           0 :         return;
    1031             :     }
    1032           0 : }
    1033             : 
    1034             : 
    1035           0 : void as2js_compiler::list_archive()
    1036             : {
    1037           0 :     if(f_filenames.size() != 1)
    1038             :     {
    1039           0 :         ++f_error_count;
    1040             :         std::cerr
    1041           0 :             << "error: expected exactly one filename with --list-archive or --extract-archive, found "
    1042           0 :             << f_filenames.size()
    1043           0 :             << " instead.\n";
    1044           0 :         return;
    1045             :     }
    1046             : 
    1047           0 :     as2js::input_stream<std::ifstream>::pointer_t in(std::make_shared<as2js::input_stream<std::ifstream>>());
    1048           0 :     in->open(f_filenames[0]);
    1049           0 :     if(!in->is_open())
    1050             :     {
    1051             :         // TODO: test again with .oar extension
    1052             :         //
    1053           0 :         ++f_error_count;
    1054             :         std::cerr
    1055             :             << "error: could not open archive \""
    1056           0 :             << f_filenames[0]
    1057           0 :             << "\".\n";
    1058           0 :         return;
    1059             :     }
    1060             : 
    1061           0 :     as2js::archive ar;
    1062           0 :     if(!ar.load(in))
    1063             :     {
    1064           0 :         ++f_error_count;
    1065             :         std::cerr
    1066             :             << "error: failed loading archive \""
    1067           0 :             << f_filenames[0]
    1068           0 :             << "\".\n";
    1069           0 :         return;
    1070             :     }
    1071             : 
    1072           0 :     as2js::rt_function::map_t functions(ar.get_functions());
    1073           0 :     std::size_t name_width(10);
    1074           0 :     for(auto const & f : functions)
    1075             :     {
    1076           0 :         name_width = std::max(f.first.length(), name_width);
    1077             :     }
    1078             :     std::cout
    1079           0 :         << "     NAME" << std::setw(name_width - 4) << ' ' << "SIZE\n";
    1080           0 :     int pos(1);
    1081           0 :     for(auto const & f : functions)
    1082             :     {
    1083             :         std::cout
    1084           0 :             << std::setw(3) << pos
    1085           0 :             << ". " << f.first
    1086           0 :             << std::setw(name_width - f.first.length()) << ' '
    1087           0 :             << f.second->get_code().size()
    1088           0 :             << "\n";
    1089           0 :         ++pos;
    1090             :     }
    1091           0 : }
    1092             : 
    1093             : 
    1094           0 : void as2js_compiler::execute()
    1095             : {
    1096           0 :     if(f_filenames.empty())
    1097             :     {
    1098           0 :         f_filenames.push_back("a.out");
    1099             :     }
    1100           0 :     else if(f_filenames.size() > 1)
    1101             :     {
    1102           0 :         ++f_error_count;
    1103             :         std::cerr
    1104           0 :             << "error: --execute expects exactly one filename.\n";
    1105           0 :         return;
    1106             :     }
    1107             : 
    1108           0 :     as2js::running_file script;
    1109           0 :     if(!script.load(f_filenames[0]))
    1110             :     {
    1111           0 :         ++f_error_count;
    1112             :         std::cerr
    1113             :             << "error: could not load \""
    1114           0 :             << f_filenames[0]
    1115           0 :             << "\" to execute code.\n";
    1116           0 :         return;
    1117             :     }
    1118             : 
    1119           0 :     for(auto const & var : f_variables)
    1120             :     {
    1121             : //std::cerr << "--- var = [" << var.second << "]\n";
    1122             :         // TODO: support all types of variables
    1123             :         //
    1124           0 :         std::string value(var.second);
    1125           0 :         std::size_t pos(var.first.find(':'));
    1126           0 :         std::string name;
    1127           0 :         std::string type;
    1128           0 :         if(pos != std::string::npos)
    1129             :         {
    1130           0 :             name = var.first.substr(0, pos);
    1131           0 :             type = var.first.substr(pos + 1);
    1132             :         }
    1133             :         else
    1134             :         {
    1135           0 :             name = var.first;
    1136           0 :             if(value.empty())
    1137             :             {
    1138           0 :                 type = "string";
    1139             :             }
    1140           0 :             else if(value.length() >= 2
    1141           0 :                  && value[0] == '"'
    1142           0 :                  && value[value.length() - 1] == '"')
    1143             :             {
    1144           0 :                 type = "string";
    1145           0 :                 value = value.substr(1, value.length() - 2);
    1146             :             }
    1147           0 :             else if(value.length() >= 2
    1148           0 :                  && value[0] == '\''
    1149           0 :                  && value[value.length() - 1] == '\'')
    1150             :             {
    1151           0 :                 type = "string";
    1152           0 :                 value = value.substr(1, value.length() - 2);
    1153             :             }
    1154             :             else
    1155             :             {
    1156           0 :                 type = "integer";
    1157           0 :                 std::size_t const max(value.length());
    1158           0 :                 for(std::size_t idx(0); idx < max; ++idx)
    1159             :                 {
    1160           0 :                     char const c(value[idx]);
    1161           0 :                     if(c == '.')
    1162             :                     {
    1163           0 :                         if(type == "integer")
    1164             :                         {
    1165           0 :                             type = "double";
    1166             :                         }
    1167             :                         else
    1168             :                         {
    1169           0 :                             type = "string";
    1170           0 :                             break;
    1171             :                         }
    1172             :                     }
    1173           0 :                     if(c < '0' || c > '9')
    1174             :                     {
    1175           0 :                         if(value == "false"
    1176           0 :                         || value == "true")
    1177             :                         {
    1178           0 :                             type = "boolean";
    1179           0 :                             break;
    1180             :                         }
    1181           0 :                         type = "string";
    1182           0 :                         break;
    1183             :                     }
    1184             :                 }
    1185             :             }
    1186             :         }
    1187           0 :         if(type == "string"
    1188           0 :         && f_three_underscores_to_space)
    1189             :         {
    1190           0 :             value = snapdev::string_replace_many(value, {{"___", " "}});
    1191             :         }
    1192           0 :         if(name.empty())
    1193             :         {
    1194           0 :             ++f_error_count;
    1195             :             std::cerr
    1196           0 :                 << "error: a variable must have a name before its ':<type>' specification.\n";
    1197           0 :             return;
    1198             :         }
    1199             : 
    1200           0 :         if(!script.has_variable(name))
    1201             :         {
    1202           0 :             if(!f_ignore_unknown_variables)
    1203             :             {
    1204           0 :                 ++f_error_count;
    1205             :                 std::cerr
    1206             :                     << "error: unknown variable \""
    1207             :                     << name
    1208             :                     << "\" in \""
    1209           0 :                     << f_filenames[0]
    1210           0 :                     << "\".\n";
    1211           0 :                 return;
    1212             :             }
    1213             :             std::cerr
    1214             :                 << "warning: variable \""
    1215             :                 << name
    1216             :                 << "\" not found in \""
    1217           0 :                 << f_filenames[0]
    1218           0 :                 << "\".\n";
    1219           0 :             continue;
    1220             :         }
    1221           0 :         type = snapdev::to_lower(type);
    1222           0 :         if(type == "integer")
    1223             :         {
    1224           0 :             std::int64_t const integer(std::stoll(value, nullptr, 0));
    1225           0 :             script.set_variable(name, integer);
    1226             :         }
    1227           0 :         else if(type == "boolean")
    1228             :         {
    1229           0 :             if(value == "true")
    1230             :             {
    1231           0 :                 script.set_variable(name, true);
    1232             :             }
    1233           0 :             else if(value == "false")
    1234             :             {
    1235           0 :                 script.set_variable(name, false);
    1236             :             }
    1237             :             else
    1238             :             {
    1239           0 :                 ++f_error_count;
    1240             :                 std::cerr
    1241           0 :                     << "error: a boolean variable must be set to \"true\" or \"false\".\n";
    1242           0 :                 return;
    1243             :             }
    1244             :         }
    1245           0 :         else if(type == "double")
    1246             :         {
    1247           0 :             double const floating_point(std::stod(value, nullptr));
    1248           0 :             script.set_variable(name, floating_point);
    1249             :         }
    1250           0 :         else if(type == "string")
    1251             :         {
    1252           0 :             script.set_variable(name, value);
    1253             :         }
    1254             :         else
    1255             :         {
    1256           0 :             ++f_error_count;
    1257             :             std::cerr
    1258             :                 << "error: unknown variable type \""
    1259             :                 << type
    1260             :                 << "\" for \""
    1261             :                 << name
    1262           0 :                 << "\".\n";
    1263           0 :             return;
    1264             :         }
    1265           0 :     }
    1266             : 
    1267           0 :     as2js::binary_result result;
    1268             : 
    1269           0 :     script.run(result);
    1270             : 
    1271           0 :     if(!f_save_to_file.empty())
    1272             :     {
    1273           0 :         script.save(f_save_to_file);
    1274             :     }
    1275             : 
    1276           0 :     switch(result.get_type())
    1277             :     {
    1278           0 :     case as2js::variable_type_t::VARIABLE_TYPE_BOOLEAN:
    1279           0 :         std::cout << std::boolalpha << result.get_boolean() << "\n";
    1280           0 :         break;
    1281             : 
    1282           0 :     case as2js::variable_type_t::VARIABLE_TYPE_INTEGER:
    1283           0 :         std::cout << result.get_integer() << "\n";
    1284           0 :         break;
    1285             : 
    1286           0 :     case as2js::variable_type_t::VARIABLE_TYPE_FLOATING_POINT:
    1287           0 :         std::cout << result.get_floating_point() << "\n";
    1288           0 :         break;
    1289             : 
    1290           0 :     case as2js::variable_type_t::VARIABLE_TYPE_STRING:
    1291           0 :         std::cout << result.get_string() << "\n";
    1292           0 :         break;
    1293             : 
    1294           0 :     default:
    1295           0 :         std::cerr << "error: unknown result type in as2js_compiler.\n";
    1296           0 :         break;
    1297             : 
    1298             :     }
    1299             : 
    1300           0 :     if(f_show_all_results)
    1301             :     {
    1302           0 :         std::size_t const count(script.variable_size());
    1303           0 :         for(std::size_t idx(0); idx < count; ++idx)
    1304             :         {
    1305           0 :             std::string name;
    1306           0 :             as2js::binary_variable * var(script.get_variable(idx, name));
    1307             : 
    1308           0 :             std::cout << name << "=";
    1309             : 
    1310             :             std::uint64_t const * data;
    1311           0 :             if(var->f_data_size <= sizeof(var->f_data))
    1312             :             {
    1313           0 :                 data = &var->f_data;
    1314             :             }
    1315             :             else
    1316             :             {
    1317           0 :                 data = reinterpret_cast<std::uint64_t const *>(var->f_data);
    1318             :             }
    1319             : 
    1320           0 :             switch(var->f_type)
    1321             :             {
    1322           0 :             case as2js::variable_type_t::VARIABLE_TYPE_UNKNOWN:
    1323           0 :                 std::cout << "<unknown variable type>\n";
    1324           0 :                 break;
    1325             : 
    1326           0 :             case as2js::variable_type_t::VARIABLE_TYPE_BOOLEAN:
    1327           0 :                 std::cout << std::boolalpha << ((*data & 255) != 0) << '\n';
    1328           0 :                 break;
    1329             : 
    1330           0 :             case as2js::variable_type_t::VARIABLE_TYPE_INTEGER:
    1331           0 :                 std::cout << *data << '\n';
    1332           0 :                 break;
    1333             : 
    1334           0 :             case as2js::variable_type_t::VARIABLE_TYPE_FLOATING_POINT:
    1335           0 :                 std::cout << *reinterpret_cast<double const *>(data) << '\n';
    1336           0 :                 break;
    1337             : 
    1338           0 :             case as2js::variable_type_t::VARIABLE_TYPE_STRING:
    1339           0 :                 std::cout << reinterpret_cast<char const *>(data) << '\n';
    1340           0 :                 break;
    1341             : 
    1342             :             }
    1343           0 :         }
    1344             :     }
    1345           0 : }
    1346             : 
    1347             : 
    1348             : 
    1349             : } // no name namespace
    1350             : 
    1351             : 
    1352          25 : int main(int argc, char *argv[])
    1353             : {
    1354             :     try
    1355             :     {
    1356          25 :         as2js_compiler::pointer_t c(std::make_shared<as2js_compiler>());
    1357          25 :         if(c->parse_command_line_options(argc, argv) != 0)
    1358             :         {
    1359           0 :             return 1;
    1360             :         }
    1361          25 :         return c->run();
    1362          25 :     }
    1363           0 :     catch(std::exception const & e)
    1364             :     {
    1365           0 :         std::cerr << "as2js: exception: " << e.what() << std::endl;
    1366           0 :         exit(1);
    1367           0 :     }
    1368             : 
    1369             :     return 0;
    1370             : }
    1371             : 
    1372             : 
    1373             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14