LCOV - code coverage report
Current view: top level - lib - optimizer_optimize.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 549 598 91.8 %
Date: 2014-11-22 Functions: 40 41 97.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* optimizer_optimize.cpp -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2014 */
       2             : 
       3             : /*
       4             : 
       5             : Copyright (c) 2005-2014 Made to Order Software Corp.
       6             : 
       7             : http://snapwebsites.org/project/as2js
       8             : 
       9             : Permission is hereby granted, free of charge, to any
      10             : person obtaining a copy of this software and
      11             : associated documentation files (the "Software"), to
      12             : deal in the Software without restriction, including
      13             : without limitation the rights to use, copy, modify,
      14             : merge, publish, distribute, sublicense, and/or sell
      15             : copies of the Software, and to permit persons to whom
      16             : the Software is furnished to do so, subject to the
      17             : following conditions:
      18             : 
      19             : The above copyright notice and this permission notice
      20             : shall be included in all copies or substantial
      21             : portions of the Software.
      22             : 
      23             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      24             : ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      25             : LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      26             : FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      27             : EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      28             : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      29             : WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      30             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      31             : SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      32             : SOFTWARE.
      33             : 
      34             : */
      35             : 
      36             : #include    "optimizer_tables.h"
      37             : 
      38             : #include    "as2js/message.h"
      39             : #include    "as2js/exceptions.h"
      40             : 
      41             : #include    <regex>
      42             : 
      43             : 
      44             : namespace as2js
      45             : {
      46             : namespace optimizer_details
      47             : {
      48             : 
      49             : 
      50             : /** \brief Hide all optimizer "optimize function" implementation details.
      51             :  *
      52             :  * This unnamed namespace is used to further hide all the optimizer
      53             :  * details.
      54             :  *
      55             :  * This namespace includes the functions used to optimize the tree of
      56             :  * nodes when a match was found earlier.
      57             :  */
      58             : namespace
      59             : {
      60             : 
      61             : 
      62             : /** \brief Apply an ADD function.
      63             :  *
      64             :  * This function adds two numbers and saves the result in the 3rd position.
      65             :  *
      66             :  * \li 0 -- source 1
      67             :  * \li 1 -- source 2
      68             :  * \li 2 -- destination
      69             :  *
      70             :  * \exception exception_internal_error
      71             :  * The function may attempt to convert the input to floating point numbers.
      72             :  * If that fails, this exception is raised. The Optimizer matching mechanism
      73             :  * should, however, prevent all such problems.
      74             :  *
      75             :  * \param[in] node_array  The array of nodes being optimized.
      76             :  * \param[in] optimize  The optimization parameters.
      77             :  */
      78           9 : void optimizer_func_ADD(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
      79             : {
      80           9 :     uint32_t src1(optimize->f_indexes[0]),
      81           9 :              src2(optimize->f_indexes[1]),
      82           9 :              dst(optimize->f_indexes[2]);
      83             : 
      84           9 :     Node::node_t type1(node_array[src1]->get_type());
      85           9 :     Node::node_t type2(node_array[src2]->get_type());
      86             : 
      87             :     // add the numbers together
      88           9 :     if(type1 == Node::node_t::NODE_INT64 && type2 == Node::node_t::NODE_INT64)
      89             :     {
      90             :         // a + b when a and b are integers
      91           6 :         Int64 i1(node_array[src1]->get_int64());
      92           6 :         Int64 i2(node_array[src2]->get_int64());
      93             :         // TODO: err on overflows?
      94           6 :         i1.set(i1.get() + i2.get());
      95           6 :         node_array[src1]->set_int64(i1);
      96             :     }
      97             :     else
      98             :     {
      99             :         // make sure a and b are floats, then do a + b as floats
     100             :         // TODO: check for NaN and other fun things?
     101           6 :         if(!node_array[src1]->to_float64()
     102           3 :         || !node_array[src2]->to_float64())
     103             :         {
     104             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
     105             :         }
     106           3 :         Float64 f1(node_array[src1]->get_float64());
     107           3 :         Float64 f2(node_array[src2]->get_float64());
     108             :         // TODO: err on overflow?
     109           3 :         f1.set(f1.get() + f2.get());
     110           3 :         node_array[src1]->set_float64(f1);
     111             :     }
     112             : 
     113             :     // save the result replacing the destination as specified
     114           9 :     node_array[dst]->replace_with(node_array[src1]);
     115           9 :     node_array[dst] = node_array[src1];
     116           9 : }
     117             : 
     118             : 
     119             : /** \brief Apply a BITWISE_AND function.
     120             :  *
     121             :  * This function AND two numbers and saves the result in the 3rd position.
     122             :  *
     123             :  * \li 0 -- source 1
     124             :  * \li 1 -- source 2
     125             :  * \li 2 -- destination
     126             :  *
     127             :  * Although the AND could be computed using 64 bits when handling integer
     128             :  * we do 32 bits to make sure that we get a result as JavaScript would.
     129             :  *
     130             :  * \exception exception_internal_error
     131             :  * The function may attempt to convert the input to floating point numbers.
     132             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     133             :  * should, however, prevent all such problems.
     134             :  *
     135             :  * \param[in] node_array  The array of nodes being optimized.
     136             :  * \param[in] optimize  The optimization parameters.
     137             :  */
     138           2 : void optimizer_func_BITWISE_AND(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     139             : {
     140           2 :     uint32_t src1(optimize->f_indexes[0]),
     141           2 :              src2(optimize->f_indexes[1]),
     142           2 :              dst(optimize->f_indexes[2]);
     143             : 
     144           4 :     if(!node_array[src1]->to_int64()
     145           2 :     || !node_array[src2]->to_int64())
     146             :     {
     147             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
     148             :     }
     149             : 
     150             :     // compute the result
     151             :     // a & b
     152           2 :     Int64 i1(node_array[src1]->get_int64());
     153           2 :     Int64 i2(node_array[src2]->get_int64());
     154           2 :     i1.set((i1.get() & i2.get()) & 0xFFFFFFFF);
     155           2 :     node_array[src1]->set_int64(i1);
     156             : 
     157             :     // save the result replacing the destination as specified
     158           2 :     node_array[dst]->replace_with(node_array[src1]);
     159           2 :     node_array[dst] = node_array[src1];
     160           2 : }
     161             : 
     162             : 
     163             : /** \brief Apply a BITWISE_NOT function.
     164             :  *
     165             :  * This function AND two numbers and saves the result in the 3rd position.
     166             :  *
     167             :  * \li 0 -- source 1
     168             :  * \li 1 -- source 2
     169             :  * \li 2 -- destination
     170             :  *
     171             :  * Although the AND could be computed using 64 bits when handling integer
     172             :  * we do 32 bits to make sure that we get a result as JavaScript would.
     173             :  *
     174             :  * \exception exception_internal_error
     175             :  * The function may attempt to convert the input to floating point numbers.
     176             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     177             :  * should, however, prevent all such problems.
     178             :  *
     179             :  * \param[in] node_array  The array of nodes being optimized.
     180             :  * \param[in] optimize  The optimization parameters.
     181             :  */
     182           2 : void optimizer_func_BITWISE_NOT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     183             : {
     184           2 :     uint32_t src(optimize->f_indexes[0]),
     185           2 :              dst(optimize->f_indexes[1]);
     186             : 
     187           2 :     if(!node_array[src]->to_int64())
     188             :     {
     189             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
     190             :     }
     191             : 
     192             :     // compute the result
     193             :     // ~a
     194           2 :     Int64 i1(node_array[src]->get_int64());
     195           2 :     i1.set(~i1.get() & 0xFFFFFFFF);
     196           2 :     node_array[src]->set_int64(i1);
     197             : 
     198             :     // save the result replacing the destination as specified
     199           2 :     node_array[dst]->replace_with(node_array[src]);
     200           2 :     node_array[dst] = node_array[src];
     201           2 : }
     202             : 
     203             : 
     204             : /** \brief Apply a BITWISE_OR function.
     205             :  *
     206             :  * This function OR two numbers and saves the result in the 3rd position.
     207             :  *
     208             :  * \li 0 -- source 1
     209             :  * \li 1 -- source 2
     210             :  * \li 2 -- destination
     211             :  *
     212             :  * Although the OR could be computed using 64 bits when handling integer
     213             :  * we do 32 bits to make sure that we get a result as JavaScript would.
     214             :  *
     215             :  * \exception exception_internal_error
     216             :  * The function may attempt to convert the input to floating point numbers.
     217             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     218             :  * should, however, prevent all such problems.
     219             :  *
     220             :  * \param[in] node_array  The array of nodes being optimized.
     221             :  * \param[in] optimize  The optimization parameters.
     222             :  */
     223           2 : void optimizer_func_BITWISE_OR(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     224             : {
     225           2 :     uint32_t src1(optimize->f_indexes[0]),
     226           2 :              src2(optimize->f_indexes[1]),
     227           2 :              dst(optimize->f_indexes[2]);
     228             : 
     229           4 :     if(!node_array[src1]->to_int64()
     230           2 :     || !node_array[src2]->to_int64())
     231             :     {
     232             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
     233             :     }
     234             : 
     235             :     // compute the result
     236             :     // a | b
     237           2 :     Int64 i1(node_array[src1]->get_int64());
     238           2 :     Int64 i2(node_array[src2]->get_int64());
     239           2 :     i1.set((i1.get() | i2.get()) & 0xFFFFFFFF);
     240           2 :     node_array[src1]->set_int64(i1);
     241             : 
     242             :     // save the result replacing the destination as specified
     243           2 :     node_array[dst]->replace_with(node_array[src1]);
     244           2 :     node_array[dst] = node_array[src1];
     245           2 : }
     246             : 
     247             : 
     248             : /** \brief Apply a BITWISE_XOR function.
     249             :  *
     250             :  * This function XOR two numbers and saves the result in the 3rd position.
     251             :  *
     252             :  * \li 0 -- source 1
     253             :  * \li 1 -- source 2
     254             :  * \li 2 -- destination
     255             :  *
     256             :  * Although the XOR could be computed using 64 bits when handling integer
     257             :  * we do 32 bits to make sure that we get a result as JavaScript would.
     258             :  *
     259             :  * \exception exception_internal_error
     260             :  * The function may attempt to convert the input to floating point numbers.
     261             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     262             :  * should, however, prevent all such problems.
     263             :  *
     264             :  * \param[in] node_array  The array of nodes being optimized.
     265             :  * \param[in] optimize  The optimization parameters.
     266             :  */
     267           3 : void optimizer_func_BITWISE_XOR(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     268             : {
     269           3 :     uint32_t src1(optimize->f_indexes[0]),
     270           3 :              src2(optimize->f_indexes[1]),
     271           3 :              dst(optimize->f_indexes[2]);
     272             : 
     273           6 :     if(!node_array[src1]->to_int64()
     274           3 :     || !node_array[src2]->to_int64())
     275             :     {
     276             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
     277             :     }
     278             : 
     279             :     // compute the result
     280             :     // a ^ b
     281           3 :     Int64 i1(node_array[src1]->get_int64());
     282           3 :     Int64 i2(node_array[src2]->get_int64());
     283           3 :     i1.set((i1.get() ^ i2.get()) & 0xFFFFFFFF);
     284           3 :     node_array[src1]->set_int64(i1);
     285             : 
     286             :     // save the result replacing the destination as specified
     287           3 :     node_array[dst]->replace_with(node_array[src1]);
     288           3 :     node_array[dst] = node_array[src1];
     289           3 : }
     290             : 
     291             : 
     292             : /** \brief Apply a COMPARE function.
     293             :  *
     294             :  * This function compares two literals and saves the result.
     295             :  *
     296             :  * \li 0 -- source 1
     297             :  * \li 1 -- source 2
     298             :  * \li 2 -- destination
     299             :  *
     300             :  * \exception exception_internal_error
     301             :  * The function does not check whether the parameters are literals. They
     302             :  * are assumed to be or can be converted as required. If a conversion
     303             :  * fails (returns false) then this exception is raised.
     304             :  *
     305             :  * \param[in] node_array  The array of nodes being optimized.
     306             :  * \param[in] optimize  The optimization parameters.
     307             :  */
     308          26 : void optimizer_func_COMPARE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     309             : {
     310          26 :     uint32_t src1(optimize->f_indexes[0]),
     311          26 :              src2(optimize->f_indexes[1]),
     312          26 :              dst(optimize->f_indexes[2]);
     313          26 :     Node::pointer_t result;
     314             : 
     315          26 :     compare_t c(Node::compare(node_array[src1], node_array[src2], Node::compare_mode_t::COMPARE_LOOSE));
     316          26 :     switch(c)
     317             :     {
     318             :         case compare_t::COMPARE_LESS:       // -1
     319             :     case compare_t::COMPARE_EQUAL:      // 0
     320             :         case compare_t::COMPARE_GREATER:    // +1
     321          21 :         result.reset(new Node(Node::node_t::NODE_INT64));
     322             :         {
     323          21 :             Int64 i;
     324          21 :             i.set(static_cast<Int64::int64_type>(c));
     325          21 :             result->set_int64(i);
     326             :         }
     327          21 :         break;
     328             : 
     329             :         case compare_t::COMPARE_UNORDERED:
     330             :         case compare_t::COMPARE_ERROR:
     331             :         case compare_t::COMPARE_UNDEFINED:
     332             :         // any invalid answer, included unordered becomes undefined
     333           5 :         result.reset(new Node(Node::node_t::NODE_UNDEFINED));
     334           5 :         break;
     335             : 
     336             :     }
     337             : 
     338             :     // save the result replacing the destination as specified
     339          26 :     node_array[dst]->replace_with(result);
     340          26 :     node_array[dst] = result;
     341          26 : }
     342             : 
     343             : 
     344             : /** \brief Apply a CONCATENATE function.
     345             :  *
     346             :  * This function concatenates two strings and save the result.
     347             :  *
     348             :  * \li 0 -- source 1
     349             :  * \li 1 -- source 2
     350             :  * \li 2 -- destination
     351             :  *
     352             :  * \exception exception_internal_error
     353             :  * The function does not check whether the parameters are strings. They
     354             :  * are assumed to be or can be converted to a string. The function uses
     355             :  * the to_string() just before the concatenation and if the conversion
     356             :  * fails (returns false) then this exception is raised.
     357             :  *
     358             :  * \param[in] node_array  The array of nodes being optimized.
     359             :  * \param[in] optimize  The optimization parameters.
     360             :  */
     361          13 : void optimizer_func_CONCATENATE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     362             : {
     363          13 :     uint32_t src1(optimize->f_indexes[0]),
     364          13 :              src2(optimize->f_indexes[1]),
     365          13 :              dst(optimize->f_indexes[2]);
     366             : 
     367          26 :     if(!node_array[src1]->to_string()
     368          13 :     || !node_array[src2]->to_string())
     369             :     {
     370             :         throw exception_internal_error("a concatenate instruction can only be used with nodes that can be converted to strings."); // LCOV_EXCL_LINE
     371             :     }
     372             : 
     373          13 :     String s1(node_array[src1]->get_string());
     374          26 :     String s2(node_array[src2]->get_string());
     375          13 :     node_array[src1]->set_string(s1 + s2);
     376             : 
     377             :     // save the result replacing the destination as specified
     378          13 :     node_array[dst]->replace_with(node_array[src1]);
     379          26 :     node_array[dst] = node_array[src1];
     380          13 : }
     381             : 
     382             : 
     383             : /** \brief Apply a DIVIDE function.
     384             :  *
     385             :  * This function divides source 1 by source 2 and saves the result in
     386             :  * the destination. Source 1 and 2 are expected to be literals.
     387             :  *
     388             :  * \li 0 -- source 1
     389             :  * \li 1 -- source 2
     390             :  * \li 2 -- destination
     391             :  *
     392             :  * \todo
     393             :  * Should we always return a floating point number when dividing?
     394             :  * At this point two integers return an integer unless the divisor
     395             :  * is zero in which case +/-Infinity is returned.
     396             :  *
     397             :  * \exception exception_internal_error
     398             :  * The function does not check whether the parameters are numbers. They
     399             :  * are assumed to be or can be converted to a number. The function uses
     400             :  * the to_float64() just before the operation and if the conversion
     401             :  * fails (returns false) then this exception is raised.
     402             :  *
     403             :  * \param[in] node_array  The array of nodes being optimized.
     404             :  * \param[in] optimize  The optimization parameters.
     405             :  */
     406           8 : void optimizer_func_DIVIDE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     407             : {
     408           8 :     uint32_t src1(optimize->f_indexes[0]),
     409           8 :              src2(optimize->f_indexes[1]),
     410           8 :              dst(optimize->f_indexes[2]);
     411             : 
     412             :     // if both are integers, keep it as an integer
     413             :     // (unless src2 is zero)
     414          16 :     if(node_array[src1]->is_int64()
     415           8 :     && node_array[src2]->is_int64())
     416             :     {
     417           3 :         Int64 i1(node_array[src1]->get_int64());
     418           3 :         Int64 i2(node_array[src2]->get_int64());
     419           3 :         if(i2.get() == 0)
     420             :         {
     421             :             // generate an warning about divisions by zero because it is not
     422             :             // unlikely an error
     423           2 :             Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
     424           2 :             msg << "division by zero of integers returning +Infinity or -Infinity.";
     425             : 
     426             :             // dividing by zero gives infinity
     427           2 :             Float64 f;
     428           2 :             f.set_infinity(); // +Infinity
     429           2 :             if(i1.get() < 0)
     430             :             {
     431             :                 // -Infinity
     432           1 :                 f.set(-f.get());
     433             :             }
     434           2 :             if(!node_array[src1]->to_float64())
     435             :             {
     436             :                 throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
     437             :             }
     438           2 :             node_array[src1]->set_float64(f);
     439             :         }
     440             :         else
     441             :         {
     442             :             // TBD: should this return a float?
     443           1 :             i1.set(i1.get() / i2.get());
     444           1 :             node_array[src1]->set_int64(i1);
     445             :         }
     446             :     }
     447             :     else
     448             :     {
     449          10 :         if(!node_array[src1]->to_float64()
     450           5 :         || !node_array[src2]->to_float64())
     451             :         {
     452             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
     453             :         }
     454             :         // make sure we keep NaN numbers as expected
     455           5 :         Float64 f1(node_array[src1]->get_float64());
     456           5 :         Float64 f2(node_array[src2]->get_float64());
     457          10 :         if(f1.is_NaN()
     458           5 :         || f2.is_NaN())
     459             :         {
     460           2 :             f1.set_NaN();
     461             :         }
     462             :         else
     463             :         {
     464           3 :             f1.set(f1.get() / f2.get());
     465             :         }
     466           5 :         node_array[src1]->set_float64(f1);
     467             :     }
     468             : 
     469             :     // save the result replacing the destination as specified
     470           8 :     node_array[dst]->replace_with(node_array[src1]);
     471           8 :     node_array[dst] = node_array[src1];
     472           8 : }
     473             : 
     474             : 
     475             : /** \brief Apply an EQUAL function.
     476             :  *
     477             :  * This function checks source 1 against source 2. If source 1 is equal to
     478             :  * source 2, then the function saves true in the destination, otherwise
     479             :  * it saves false.
     480             :  *
     481             :  * \li 0 -- source 1
     482             :  * \li 1 -- source 2
     483             :  * \li 2 -- destination
     484             :  *
     485             :  * \param[in] node_array  The array of nodes being optimized.
     486             :  * \param[in] optimize  The optimization parameters.
     487             :  */
     488          40 : void optimizer_func_EQUAL(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     489             : {
     490          40 :     uint32_t src1(optimize->f_indexes[0]),
     491          40 :              src2(optimize->f_indexes[1]),
     492          40 :              dst(optimize->f_indexes[2]);
     493             : 
     494          40 :     compare_t c(Node::compare(node_array[src1], node_array[src2], Node::compare_mode_t::COMPARE_LOOSE));
     495             :     Node::pointer_t result(new Node(c == compare_t::COMPARE_EQUAL
     496             :                                     ? Node::node_t::NODE_TRUE
     497          40 :                                     : Node::node_t::NODE_FALSE));
     498             : 
     499             :     // save the result replacing the destination as specified
     500          40 :     node_array[dst]->replace_with(result);
     501          40 :     node_array[dst] = result;
     502          40 : }
     503             : 
     504             : 
     505             : /** \brief Apply a LESS function.
     506             :  *
     507             :  * This function checks source 1 against source 2. If source 1 is smaller
     508             :  * than source 2, then the function saves true in the destination, otherwise
     509             :  * it saves false.
     510             :  *
     511             :  * \li 0 -- source 1
     512             :  * \li 1 -- source 2
     513             :  * \li 2 -- destination
     514             :  *
     515             :  * \param[in] node_array  The array of nodes being optimized.
     516             :  * \param[in] optimize  The optimization parameters.
     517             :  */
     518          40 : void optimizer_func_LESS(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     519             : {
     520          40 :     uint32_t src1(optimize->f_indexes[0]),
     521          40 :              src2(optimize->f_indexes[1]),
     522          40 :              dst(optimize->f_indexes[2]);
     523             : 
     524          40 :     compare_t c(Node::compare(node_array[src1], node_array[src2], Node::compare_mode_t::COMPARE_LOOSE));
     525             :     Node::pointer_t result(new Node(c == compare_t::COMPARE_LESS
     526             :                                     ? Node::node_t::NODE_TRUE
     527          40 :                                     : Node::node_t::NODE_FALSE));
     528             : 
     529             :     // save the result replacing the destination as specified
     530          40 :     node_array[dst]->replace_with(result);
     531          40 :     node_array[dst] = result;
     532          40 : }
     533             : 
     534             : 
     535             : /** \brief Apply a LESS_EQUAL function.
     536             :  *
     537             :  * This function checks source 1 against source 2. If source 1 is smaller
     538             :  * than source 2, then the function saves true in the destination, otherwise
     539             :  * it saves false.
     540             :  *
     541             :  * \li 0 -- source 1
     542             :  * \li 1 -- source 2
     543             :  * \li 2 -- destination
     544             :  *
     545             :  * \param[in] node_array  The array of nodes being optimized.
     546             :  * \param[in] optimize  The optimization parameters.
     547             :  */
     548          40 : void optimizer_func_LESS_EQUAL(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     549             : {
     550          40 :     uint32_t src1(optimize->f_indexes[0]),
     551          40 :              src2(optimize->f_indexes[1]),
     552          40 :              dst(optimize->f_indexes[2]);
     553             : 
     554          40 :     compare_t const c(Node::compare(node_array[src1], node_array[src2], Node::compare_mode_t::COMPARE_LOOSE));
     555             :     Node::pointer_t result(new Node(c == compare_t::COMPARE_LESS
     556          28 :                                  || c == compare_t::COMPARE_EQUAL
     557             :                                         ? Node::node_t::NODE_TRUE
     558          66 :                                         : Node::node_t::NODE_FALSE));
     559             : 
     560             :     // save the result replacing the destination as specified
     561          40 :     node_array[dst]->replace_with(result);
     562          40 :     node_array[dst] = result;
     563          40 : }
     564             : 
     565             : 
     566             : /** \brief Apply a LOGICAL_NOT function.
     567             :  *
     568             :  * This function applies a logical NOT and saves the result in the
     569             :  * 2nd position.
     570             :  *
     571             :  * The logical NOT is applied whatever the input literal after a conversion
     572             :  * to Boolean. If the conversion fails, then an exception is raised.
     573             :  *
     574             :  * \li 0 -- source
     575             :  * \li 1 -- destination
     576             :  *
     577             :  * \exception exception_internal_error
     578             :  * The function may attempt to convert the input to a Boolean value.
     579             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     580             :  * should, however, prevent all such problems.
     581             :  *
     582             :  * \param[in] node_array  The array of nodes being optimized.
     583             :  * \param[in] optimize  The optimization parameters.
     584             :  */
     585          50 : void optimizer_func_LOGICAL_NOT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     586             : {
     587          50 :     uint32_t src(optimize->f_indexes[0]),
     588          50 :              dst(optimize->f_indexes[1]);
     589             : 
     590          50 :     if(!node_array[src]->to_boolean())
     591             :     {
     592             :         throw exception_internal_error("optimizer used function to_boolean() against a node that cannot be converted to a Boolean."); // LCOV_EXCL_LINE
     593             :     }
     594          50 :     bool b(node_array[src]->get_boolean());
     595          50 :     node_array[src]->set_boolean(!b);
     596             : 
     597             :     // save the result replacing the destination as specified
     598          50 :     node_array[dst]->replace_with(node_array[src]);
     599          50 :     node_array[dst] = node_array[src];
     600          50 : }
     601             : 
     602             : 
     603             : /** \brief Apply a LOGICAL_XOR function.
     604             :  *
     605             :  * This function applies a logical XOR between the two sources and saves
     606             :  * the result in the 2nd position.
     607             :  *
     608             :  * The logical XOR is applied whatever the literals after a conversion
     609             :  * to Boolean. If the conversion fails, then an exception is raised.
     610             :  *
     611             :  * \li 0 -- first source
     612             :  * \li 1 -- second source
     613             :  * \li 2 -- destination
     614             :  *
     615             :  * \warning
     616             :  * The first source will be modified before replacing destination.
     617             :  *
     618             :  * \exception exception_internal_error
     619             :  * The function may attempt to convert the inputs to Boolean values.
     620             :  * If that fails, this exception is raised. The Optimizer matching mechanism
     621             :  * should, however, prevent all such problems.
     622             :  *
     623             :  * \param[in] node_array  The array of nodes being optimized.
     624             :  * \param[in] optimize  The optimization parameters.
     625             :  */
     626          10 : void optimizer_func_LOGICAL_XOR(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     627             : {
     628          10 :     uint32_t src1(optimize->f_indexes[0]),
     629          10 :              src2(optimize->f_indexes[1]),
     630          10 :              dst(optimize->f_indexes[2]);
     631             : 
     632          10 :     Node::node_t n1(node_array[src1]->to_boolean_type_only());
     633          10 :     Node::node_t n2(node_array[src2]->to_boolean_type_only());
     634          10 :     if((n1 != Node::node_t::NODE_TRUE && n1 != Node::node_t::NODE_FALSE)
     635          10 :     || (n2 != Node::node_t::NODE_TRUE && n2 != Node::node_t::NODE_FALSE))
     636             :     {
     637             :         throw exception_internal_error("optimizer used function to_boolean_type_only() against a node that cannot be converted to a Boolean."); // LCOV_EXCL_LINE
     638             :     }
     639          10 :     if(n1 == n2)
     640             :     {
     641             :         // if false, return the Boolean false
     642           4 :         node_array[src1]->to_boolean();
     643           4 :         node_array[src1]->set_boolean(false);
     644             :     }
     645             :     else
     646             :     {
     647             :         // if true, return the input as is
     648           6 :         if(n1 == Node::node_t::NODE_FALSE)
     649             :         {
     650             :             // src2 is the result if src1 represents false
     651           3 :             src1 = src2;
     652             :         }
     653             :     }
     654             : 
     655             :     // save the result replacing the destination as specified
     656          10 :     node_array[dst]->replace_with(node_array[src1]);
     657          10 :     node_array[dst] = node_array[src1];
     658          10 : }
     659             : 
     660             : 
     661             : /** \brief Apply a MODULO function.
     662             :  *
     663             :  * This function divides source 1 by source 2 and saves the rest in
     664             :  * the destination. Source 1 and 2 are expected to be literals.
     665             :  *
     666             :  * \li 0 -- source 1
     667             :  * \li 1 -- source 2
     668             :  * \li 2 -- destination
     669             :  *
     670             :  * If the divisor is zero, the function returns NaN.
     671             :  *
     672             :  * \exception exception_internal_error
     673             :  * The function does not check whether the parameters are numbers. They
     674             :  * are assumed to be or can be converted to a number. The function uses
     675             :  * the to_float64() just before the operation and if the conversion
     676             :  * fails (returns false) then this exception is raised.
     677             :  *
     678             :  * \param[in] node_array  The array of nodes being optimized.
     679             :  * \param[in] optimize  The optimization parameters.
     680             :  */
     681           8 : void optimizer_func_MODULO(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     682             : {
     683           8 :     uint32_t src1(optimize->f_indexes[0]),
     684           8 :              src2(optimize->f_indexes[1]),
     685           8 :              dst(optimize->f_indexes[2]);
     686             : 
     687             :     // if both are integers, keep it as an integer
     688             :     // (unless src2 is zero)
     689          16 :     if(node_array[src1]->is_int64()
     690           8 :     && node_array[src2]->is_int64())
     691             :     {
     692           3 :         Int64 i1(node_array[src1]->get_int64());
     693           3 :         Int64 i2(node_array[src2]->get_int64());
     694           3 :         if(i2.get() == 0)
     695             :         {
     696             :             // generate an warning about divisions by zero because it is not
     697             :             // unlikely an error
     698           2 :             Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
     699           2 :             msg << "division by zero for a modulo of integers returning NaN.";
     700             : 
     701             :             // dividing by zero gives infinity
     702           2 :             Float64 f;
     703           2 :             f.set_NaN();
     704           2 :             if(!node_array[src1]->to_float64())
     705             :             {
     706             :                 throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
     707             :             }
     708           2 :             node_array[src1]->set_float64(f);
     709             :         }
     710             :         else
     711             :         {
     712             :             // TBD: should this return a float?
     713           1 :             i1.set(i1.get() % i2.get());
     714           1 :             node_array[src1]->set_int64(i1);
     715             :         }
     716             :     }
     717             :     else
     718             :     {
     719          10 :         if(!node_array[src1]->to_float64()
     720           5 :         || !node_array[src2]->to_float64())
     721             :         {
     722             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
     723             :         }
     724             :         // make sure we keep NaN numbers as expected
     725           5 :         Float64 f1(node_array[src1]->get_float64());
     726           5 :         Float64 f2(node_array[src2]->get_float64());
     727          10 :         if(f1.is_NaN()
     728           5 :         || f2.is_NaN())
     729             :         {
     730           2 :             f1.set_NaN();
     731             :         }
     732             :         else
     733             :         {
     734           3 :             f1.set(fmod(f1.get(), f2.get()));
     735             :         }
     736           5 :         node_array[src1]->set_float64(f1);
     737             :     }
     738             : 
     739             :     // save the result replacing the destination as specified
     740           8 :     node_array[dst]->replace_with(node_array[src1]);
     741           8 :     node_array[dst] = node_array[src1];
     742           8 : }
     743             : 
     744             : 
     745             : /** \brief Apply a MOVE function.
     746             :  *
     747             :  * This function moves a node to another. In most cases, you move a child
     748             :  * to the parent. For example in
     749             :  *
     750             :  * \code
     751             :  *      a := b + 0;
     752             :  * \endcode
     753             :  *
     754             :  * You could move b in the position of the '+' operator so the expression
     755             :  * now looks like:
     756             :  *
     757             :  * \code
     758             :  *      a := b;
     759             :  * \endcode
     760             :  *
     761             :  * (note that in this case we were optimizing 'b + 0' at this point)
     762             :  *
     763             :  * \li 0 -- source
     764             :  * \li 1 -- destination
     765             :  *
     766             :  * \param[in] node_array  The array of nodes being optimized.
     767             :  * \param[in] optimize  The optimization parameters.
     768             :  */
     769         108 : void optimizer_func_MOVE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     770             : {
     771         108 :     uint32_t src(optimize->f_indexes[0]),
     772         108 :              dst(optimize->f_indexes[1]);
     773             : 
     774             :     // move the source in place of the destination
     775         108 :     node_array[dst]->replace_with(node_array[src]);
     776         108 :     node_array[dst] = node_array[src];
     777         108 : }
     778             : 
     779             : 
     780             : /** \brief Apply a MATCH function.
     781             :  *
     782             :  * This function checks whether the left handside matches the regular
     783             :  * expression in the right handside and returns true if it does and
     784             :  * false if it does not.
     785             :  *
     786             :  * \li 0 -- source 1
     787             :  * \li 1 -- source 2
     788             :  * \li 2 -- destination
     789             :  *
     790             :  * \exception exception_internal_error
     791             :  * The function does not check whether the parameters are numbers. They
     792             :  * are assumed to be or can be converted to a number. The function uses
     793             :  * the to_float64() just before the operation and if the conversion
     794             :  * fails (returns false) then this exception is raised.
     795             :  *
     796             :  * \param[in] node_array  The array of nodes being optimized.
     797             :  * \param[in] optimize  The optimization parameters.
     798             :  */
     799           0 : void optimizer_func_MATCH(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     800             : {
     801           0 :     uint32_t src1(optimize->f_indexes[0]),
     802           0 :              src2(optimize->f_indexes[1]),
     803           0 :              dst(optimize->f_indexes[2]);
     804             : 
     805             :     // if both are integers, keep it as an integer
     806           0 :     std::regex::flag_type regex_flags(std::regex_constants::ECMAScript | std::regex_constants::nosubs);
     807           0 :     String regex(node_array[src2]->get_string());
     808           0 :     if(regex[0] == '/')
     809             :     {
     810           0 :         String::size_type pos(regex.find_last_of('/'));
     811           0 :         String flags(regex.substr(pos + 1));
     812           0 :         regex = regex.substr(1, pos - 1); // remove the /.../
     813           0 :         if(flags.find('i') != String::npos)
     814             :         {
     815           0 :             regex_flags |= std::regex_constants::icase;
     816           0 :         }
     817             :     }
     818             :     // g++ implementation of regex is still quite limited in g++ 4.8.x
     819             :     // if you have 4.9.0, the following should work nicely for you, otherwise
     820             :     // it does nothing...
     821             :     // http://stackoverflow.com/questions/12530406/is-gcc4-7-buggy-about-regular-expressions
     822           0 :     int match_result(-1);
     823             :     try
     824             :     {
     825           0 :         std::basic_regex<as_char_t> js_regex(regex, regex_flags);
     826           0 :         std::match_results<String::const_iterator> js_match;
     827           0 :         std::regex_search(node_array[src1]->get_string(), js_match, js_regex);
     828           0 :         match_result = js_match.empty() ? 1 : 0;
     829             :     }
     830             :     catch(std::regex_error const&)
     831             :     {
     832             :     }
     833             :     catch(std::bad_cast const&)
     834             :     {
     835             :     }
     836             : 
     837           0 :     Node::pointer_t result;
     838           0 :     if(match_result == -1)
     839             :     {
     840             :         // the regular expression is not valid, so we cannot optimize it
     841             :         // to true or false, instead we generate an error now and transform
     842             :         // the code to a throw
     843             :         //
     844             :         //    throw new SyntaxError(errmsg, fileName, lineNumber);
     845             :         //
     846             :         // important note: any optimization has to do something or the
     847             :         //                 optimizer tries again indefinitely...
     848             :         //
     849           0 :         result.reset(new Node(Node::node_t::NODE_THROW));
     850             :         // TODO: we need to create a SyntaxError object
     851             : 
     852           0 :         Node::pointer_t call(new Node(Node::node_t::NODE_CALL));
     853           0 :         result->append_child(call);
     854             : 
     855           0 :         Node::pointer_t syntax_error(new Node(Node::node_t::NODE_IDENTIFIER));
     856           0 :         syntax_error->set_string("SyntaxError");
     857           0 :         call->append_child(syntax_error);
     858             : 
     859           0 :         Node::pointer_t params(new Node(Node::node_t::NODE_LIST));
     860           0 :         call->append_child(params);
     861             : 
     862           0 :         Node::pointer_t message(new Node(Node::node_t::NODE_STRING));
     863           0 :         String errmsg("regular expression \"");
     864           0 :         errmsg += regex;
     865           0 :         errmsg += "\" could not be compiled by std::regex.";
     866           0 :         message->set_string(errmsg);
     867           0 :         params->append_child(message);
     868             : 
     869           0 :         Position const& pos(node_array[src2]->get_position());
     870             : 
     871           0 :         Node::pointer_t filename(new Node(Node::node_t::NODE_STRING));
     872           0 :         filename->set_string(pos.get_filename());
     873           0 :         params->append_child(filename);
     874             : 
     875           0 :         Node::pointer_t line_number(new Node(Node::node_t::NODE_INT64));
     876           0 :         Int64 ln;
     877           0 :         ln.set(pos.get_line());
     878           0 :         line_number->set_int64(ln);
     879           0 :         params->append_child(line_number);
     880             : 
     881           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_NUMBER, pos);
     882           0 :         msg << errmsg;
     883             :     }
     884             :     else
     885             :     {
     886           0 :         result.reset(new Node(match_result == 0 ? Node::node_t::NODE_FALSE : Node::node_t::NODE_TRUE));
     887             :     }
     888             : 
     889             :     // save the result replacing the destination as specified
     890           0 :     node_array[dst]->replace_with(result);
     891           0 :     node_array[dst] = result;
     892           0 : }
     893             : 
     894             : 
     895             : /** \brief Apply a MAXIMUM function.
     896             :  *
     897             :  * This function compares two values and keep the largest one.
     898             :  *
     899             :  * \li 0 -- source 1
     900             :  * \li 1 -- source 2
     901             :  * \li 2 -- destination
     902             :  *
     903             :  * \param[in] node_array  The array of nodes being optimized.
     904             :  * \param[in] optimize  The optimization parameters.
     905             :  */
     906           3 : void optimizer_func_MAXIMUM(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     907             : {
     908           3 :     uint32_t src1(optimize->f_indexes[0]),
     909           3 :              src2(optimize->f_indexes[1]),
     910           3 :              dst(optimize->f_indexes[2]);
     911             : 
     912           3 :     Node::pointer_t result;
     913             : 
     914           6 :     Node::pointer_t n1(node_array[src1]);
     915           6 :     Node::pointer_t n2(node_array[src2]);
     916           3 :     if(n1->is_float64() && n1->get_float64().is_NaN())
     917             :     {
     918           1 :         result = n2;
     919             :     }
     920           2 :     else if(n2->is_float64() && n2->get_float64().is_NaN())
     921             :     {
     922           1 :         result = n1;
     923             :     }
     924             :     else
     925             :     {
     926           1 :         compare_t const c(Node::compare(n1, n2, Node::compare_mode_t::COMPARE_LOOSE));
     927           1 :         result = c == compare_t::COMPARE_GREATER ? n1 : n2;
     928             :     }
     929             : 
     930             :     // save the result replacing the destination as specified
     931           3 :     node_array[dst]->replace_with(result);
     932           6 :     node_array[dst] = result;
     933           3 : }
     934             : 
     935             : 
     936             : /** \brief Apply a MINIMUM function.
     937             :  *
     938             :  * This function compares two values and keep the smallest one.
     939             :  *
     940             :  * \li 0 -- source 1
     941             :  * \li 1 -- source 2
     942             :  * \li 2 -- destination
     943             :  *
     944             :  * \param[in] node_array  The array of nodes being optimized.
     945             :  * \param[in] optimize  The optimization parameters.
     946             :  */
     947           3 : void optimizer_func_MINIMUM(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     948             : {
     949           3 :     uint32_t src1(optimize->f_indexes[0]),
     950           3 :              src2(optimize->f_indexes[1]),
     951           3 :              dst(optimize->f_indexes[2]);
     952             : 
     953           3 :     Node::pointer_t result;
     954             : 
     955           6 :     Node::pointer_t n1(node_array[src1]);
     956           6 :     Node::pointer_t n2(node_array[src2]);
     957           3 :     if(n1->is_float64() && n1->get_float64().is_NaN())
     958             :     {
     959           1 :         result = n2;
     960             :     }
     961           2 :     else if(n2->is_float64() && n2->get_float64().is_NaN())
     962             :     {
     963           1 :         result = n1;
     964             :     }
     965             :     else
     966             :     {
     967           1 :         compare_t const c(Node::compare(n1, n2, Node::compare_mode_t::COMPARE_LOOSE));
     968           1 :         result = c == compare_t::COMPARE_LESS ? n1 : n2;
     969             :     }
     970             : 
     971             :     // save the result replacing the destination as specified
     972           3 :     node_array[dst]->replace_with(result);
     973           6 :     node_array[dst] = result;
     974           3 : }
     975             : 
     976             : 
     977             : /** \brief Apply a MULTIPLY function.
     978             :  *
     979             :  * This function multiplies source 1 by source 2 and saves the result in
     980             :  * the destination. Source 1 and 2 are expected to be literals.
     981             :  *
     982             :  * \li 0 -- source 1
     983             :  * \li 1 -- source 2
     984             :  * \li 2 -- destination
     985             :  *
     986             :  * \exception exception_internal_error
     987             :  * The function does not check whether the parameters are numbers. They
     988             :  * are assumed to be or can be converted to a number. The function uses
     989             :  * the to_float64() just before the operation and if the conversion
     990             :  * fails (returns false) then this exception is raised.
     991             :  *
     992             :  * \param[in] node_array  The array of nodes being optimized.
     993             :  * \param[in] optimize  The optimization parameters.
     994             :  */
     995           6 : void optimizer_func_MULTIPLY(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
     996             : {
     997           6 :     uint32_t src1(optimize->f_indexes[0]),
     998           6 :              src2(optimize->f_indexes[1]),
     999           6 :              dst(optimize->f_indexes[2]);
    1000             : 
    1001             :     // if both are integers, keep it as an integer
    1002          12 :     if(node_array[src1]->is_int64()
    1003           6 :     && node_array[src2]->is_int64())
    1004             :     {
    1005           1 :         Int64 i1(node_array[src1]->get_int64());
    1006           1 :         Int64 i2(node_array[src2]->get_int64());
    1007           1 :         i1.set(i1.get() * i2.get());
    1008           1 :         node_array[src1]->set_int64(i1);
    1009             :     }
    1010             :     else
    1011             :     {
    1012          10 :         if(!node_array[src1]->to_float64()
    1013           5 :         || !node_array[src2]->to_float64())
    1014             :         {
    1015             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
    1016             :         }
    1017             :         // make sure we keep NaN numbers as expected
    1018           5 :         Float64 f1(node_array[src1]->get_float64());
    1019           5 :         Float64 f2(node_array[src2]->get_float64());
    1020          10 :         if(f1.is_NaN()
    1021           5 :         || f2.is_NaN())
    1022             :         {
    1023           2 :             f1.set_NaN();
    1024             :         }
    1025             :         else
    1026             :         {
    1027           3 :             f1.set(f1.get() * f2.get());
    1028             :         }
    1029           5 :         node_array[src1]->set_float64(f1);
    1030             :     }
    1031             : 
    1032             :     // save the result replacing the destination as specified
    1033           6 :     node_array[dst]->replace_with(node_array[src1]);
    1034           6 :     node_array[dst] = node_array[src1];
    1035           6 : }
    1036             : 
    1037             : 
    1038             : /** \brief Apply a NEGATE function.
    1039             :  *
    1040             :  * This function negate a number and saves the result in the 2nd position.
    1041             :  *
    1042             :  * \li 0 -- source
    1043             :  * \li 1 -- destination
    1044             :  *
    1045             :  * \exception exception_internal_error
    1046             :  * The function may attempt to convert the input to a floating point number.
    1047             :  * If that fails, this exception is raised. The Optimizer matching mechanism
    1048             :  * should, however, prevent all such problems.
    1049             :  *
    1050             :  * \param[in] node_array  The array of nodes being optimized.
    1051             :  * \param[in] optimize  The optimization parameters.
    1052             :  */
    1053          71 : void optimizer_func_NEGATE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1054             : {
    1055          71 :     uint32_t src(optimize->f_indexes[0]),
    1056          71 :              dst(optimize->f_indexes[1]);
    1057             : 
    1058          71 :     Node::node_t type(node_array[src]->get_type());
    1059             : 
    1060             :     // negate the integer or the float
    1061          71 :     if(type == Node::node_t::NODE_INT64)
    1062             :     {
    1063          14 :         Int64 i(node_array[src]->get_int64());
    1064          14 :         i.set(-i.get());
    1065          14 :         node_array[src]->set_int64(i);
    1066             :     }
    1067             :     else
    1068             :     {
    1069             :         // make sure a and b are floats, then do a + b as floats
    1070             :         // TODO: check for NaN and other fun things?
    1071          57 :         if(!node_array[src]->to_float64())
    1072             :         {
    1073             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
    1074             :         }
    1075          57 :         Float64 f(node_array[src]->get_float64());
    1076          57 :         f.set(-f.get());
    1077          57 :         node_array[src]->set_float64(f);
    1078             :     }
    1079             : 
    1080             :     // save the result replacing the destination as specified
    1081          71 :     node_array[dst]->replace_with(node_array[src]);
    1082          71 :     node_array[dst] = node_array[src];
    1083          71 : }
    1084             : 
    1085             : 
    1086             : /** \brief Apply a POWER function.
    1087             :  *
    1088             :  * This function computes source 1 power source 2 and saves the result in
    1089             :  * the destination. Source 1 and 2 are expected to be literals.
    1090             :  *
    1091             :  * \li 0 -- source 1
    1092             :  * \li 1 -- source 2
    1093             :  * \li 2 -- destination
    1094             :  *
    1095             :  * \exception exception_internal_error
    1096             :  * The function does not check whether the parameters are numbers. They
    1097             :  * are assumed to be or can be converted to a number. The function uses
    1098             :  * the to_float64() just before the operation and if the conversion
    1099             :  * fails (returns false) then this exception is raised.
    1100             :  *
    1101             :  * \param[in] node_array  The array of nodes being optimized.
    1102             :  * \param[in] optimize  The optimization parameters.
    1103             :  */
    1104           6 : void optimizer_func_POWER(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1105             : {
    1106           6 :     uint32_t src1(optimize->f_indexes[0]),
    1107           6 :              src2(optimize->f_indexes[1]),
    1108           6 :              dst(optimize->f_indexes[2]);
    1109             : 
    1110             :     // for powers, we always return a floating point
    1111             :     // (think of negative numbers...)
    1112          12 :     if(!node_array[src1]->to_float64()
    1113           6 :     || !node_array[src2]->to_float64())
    1114             :     {
    1115             :         throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
    1116             :     }
    1117             : 
    1118             :     // make sure we keep NaN numbers as expected
    1119           6 :     Float64 f1(node_array[src1]->get_float64());
    1120           6 :     Float64 f2(node_array[src2]->get_float64());
    1121          12 :     if(f1.is_NaN()
    1122           6 :     || f2.is_NaN())
    1123             :     {
    1124           2 :         f1.set_NaN();
    1125             :     }
    1126             :     else
    1127             :     {
    1128           4 :         f1.set(pow(f1.get(), f2.get()));
    1129             :     }
    1130           6 :     node_array[src1]->set_float64(f1);
    1131             : 
    1132             :     // save the result replacing the destination as specified
    1133           6 :     node_array[dst]->replace_with(node_array[src1]);
    1134           6 :     node_array[dst] = node_array[src1];
    1135           6 : }
    1136             : 
    1137             : 
    1138             : /** \brief Apply a REMOVE function.
    1139             :  *
    1140             :  * This function removes a node from another. In most cases, you remove one
    1141             :  * of the child of a binary operator or similar
    1142             :  *
    1143             :  * \code
    1144             :  *      a + 0;
    1145             :  * \endcode
    1146             :  *
    1147             :  * You could remove the zero to get:
    1148             :  *
    1149             :  * \code
    1150             :  *      +a;
    1151             :  * \endcode
    1152             :  *
    1153             :  * \li 0 -- source
    1154             :  *
    1155             :  * \param[in] node_array  The array of nodes being optimized.
    1156             :  * \param[in] optimize  The optimization parameters.
    1157             :  */
    1158           6 : void optimizer_func_REMOVE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1159             : {
    1160           6 :     uint32_t src(optimize->f_indexes[0]);
    1161             : 
    1162           6 :     if(src == 0)
    1163             :     {
    1164             :         // ah... we cannot remove this one, instead mark it as unknown
    1165           2 :         node_array[src]->to_unknown();
    1166             :     }
    1167             :     else
    1168             :     {
    1169             :         // simply remove from the parent, the smart pointers take care of the rest
    1170           4 :         node_array[src]->set_parent(nullptr);
    1171             :     }
    1172           6 : }
    1173             : 
    1174             : 
    1175             : /** \brief Apply an ROTATE_LEFT function.
    1176             :  *
    1177             :  * This function rotates the first number to the left by the number of bits
    1178             :  * indicated by the second number and saves the result in the 3rd position.
    1179             :  *
    1180             :  * \li 0 -- source 1
    1181             :  * \li 1 -- source 2
    1182             :  * \li 2 -- destination
    1183             :  *
    1184             :  * Although the rotate left could be computed using 64 bits when handling
    1185             :  * integer we do 32 bits to make sure that we get a result as
    1186             :  * JavaScript would.
    1187             :  *
    1188             :  * \exception exception_internal_error
    1189             :  * The function attempts to convert the input to integer numbers.
    1190             :  * If that fails, this exception is raised. The Optimizer matching
    1191             :  * mechanism should, however, prevent all such problems.
    1192             :  *
    1193             :  * \param[in] node_array  The array of nodes being optimized.
    1194             :  * \param[in] optimize  The optimization parameters.
    1195             :  */
    1196           3 : void optimizer_func_ROTATE_LEFT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1197             : {
    1198           3 :     uint32_t src1(optimize->f_indexes[0]),
    1199           3 :              src2(optimize->f_indexes[1]),
    1200           3 :              dst(optimize->f_indexes[2]);
    1201             : 
    1202           6 :     if(!node_array[src1]->to_int64()
    1203           3 :     || !node_array[src2]->to_int64())
    1204             :     {
    1205             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
    1206             :     }
    1207             : 
    1208             :     // compute the result
    1209             :     // a >% b
    1210           3 :     Int64 i1(node_array[src1]->get_int64());
    1211           3 :     Int64 i2(node_array[src2]->get_int64());
    1212           3 :     Int64::int64_type v2(i2.get());
    1213           3 :     Int64::int64_type v2_and(v2 & 0x1F);
    1214           3 :     if(v2 < 0)
    1215             :     {
    1216           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1217           1 :         msg << "this static rotate amount is less than zero. " << v2_and << " will be used instead of " << v2 << ".";
    1218             :     }
    1219           2 :     else if(v2 >= 32)
    1220             :     {
    1221           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1222           1 :         msg << "this static rotate amount is larger than 31. " << v2_and << " will be used instead of " << v2 << ".";
    1223             :     }
    1224             :     // TODO: warn about v1 being larger than 32 bits?
    1225           3 :     uint32_t v1(i1.get());
    1226           3 :     if(v2_and != 0)
    1227             :     {
    1228           3 :         v1 = (v1 << v2_and) | (v1 >> (32 - v2_and));
    1229             :     }
    1230           3 :     i1.set(v1);
    1231           3 :     node_array[src1]->set_int64(i1);
    1232             : 
    1233             :     // save the result replacing the destination as specified
    1234           3 :     node_array[dst]->replace_with(node_array[src1]);
    1235           3 :     node_array[dst] = node_array[src1];
    1236           3 : }
    1237             : 
    1238             : 
    1239             : /** \brief Apply an ROTATE_RIGHT function.
    1240             :  *
    1241             :  * This function rotates the first number to the left by the number of bits
    1242             :  * indicated by the second number and saves the result in the 3rd position.
    1243             :  *
    1244             :  * \li 0 -- source 1
    1245             :  * \li 1 -- source 2
    1246             :  * \li 2 -- destination
    1247             :  *
    1248             :  * Although the rotate left could be computed using 64 bits when handling
    1249             :  * integer we do 32 bits to make sure that we get a result as
    1250             :  * JavaScript would.
    1251             :  *
    1252             :  * \exception exception_internal_error
    1253             :  * The function attempts to convert the input to integer numbers.
    1254             :  * If that fails, this exception is raised. The Optimizer matching
    1255             :  * mechanism should, however, prevent all such problems.
    1256             :  *
    1257             :  * \param[in] node_array  The array of nodes being optimized.
    1258             :  * \param[in] optimize  The optimization parameters.
    1259             :  */
    1260           8 : void optimizer_func_ROTATE_RIGHT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1261             : {
    1262           8 :     uint32_t src1(optimize->f_indexes[0]),
    1263           8 :              src2(optimize->f_indexes[1]),
    1264           8 :              dst(optimize->f_indexes[2]);
    1265             : 
    1266          16 :     if(!node_array[src1]->to_int64()
    1267           8 :     || !node_array[src2]->to_int64())
    1268             :     {
    1269             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
    1270             :     }
    1271             : 
    1272             :     // compute the result
    1273             :     // a >% b
    1274           8 :     Int64 i1(node_array[src1]->get_int64());
    1275           8 :     Int64 i2(node_array[src2]->get_int64());
    1276           8 :     Int64::int64_type v2(i2.get());
    1277           8 :     Int64::int64_type v2_and(v2 & 0x1F);
    1278           8 :     if(v2 < 0)
    1279             :     {
    1280           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1281           1 :         msg << "this static rotate amount is less than zero. " << v2_and << " will be used instead of " << v2 << ".";
    1282             :     }
    1283           7 :     else if(v2 >= 32)
    1284             :     {
    1285           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1286           1 :         msg << "this static rotate amount is larger than 31. " << v2_and << " will be used instead of " << v2 << ".";
    1287             :     }
    1288             :     // TODO: warn about v1 being larger than 32 bits?
    1289           8 :     uint32_t v1(i1.get());
    1290           8 :     if(v2_and != 0)
    1291             :     {
    1292           4 :         v1 = (v1 >> v2_and) | (v1 << (32 - v2_and));
    1293             :     }
    1294           8 :     i1.set(v1);
    1295           8 :     node_array[src1]->set_int64(i1);
    1296             : 
    1297             :     // save the result replacing the destination as specified
    1298           8 :     node_array[dst]->replace_with(node_array[src1]);
    1299           8 :     node_array[dst] = node_array[src1];
    1300           8 : }
    1301             : 
    1302             : 
    1303             : ///** \brief Apply a SET_FLOAT function.
    1304             : // *
    1305             : // * This function sets the value of a float node. This is used when an
    1306             : // * optimization can determine the result of a numeric expression and
    1307             : // * a simple float can be set as the result.
    1308             : // *
    1309             : // * For example, a bitwise operation with NaN returns zero. This
    1310             : // * function can be used for that purpose.
    1311             : // *
    1312             : // * \li 0 -- node to be modified, it must be a NODE_FLOAT64
    1313             : // * \li 1 -- dividend (taken as a signed 16 bit value)
    1314             : // * \li 2 -- divisor (unsigned)
    1315             : // *
    1316             : // * The value is offset 1 divided by offset 2. Note however that
    1317             : // * both of those values are only 16 bits... If the divisor is zero
    1318             : // * then we use NaN as the value.
    1319             : // *
    1320             : // * \param[in] node_array  The array of nodes being optimized.
    1321             : // * \param[in] optimize  The optimization parameters.
    1322             : // */
    1323             : //void optimizer_func_SET_FLOAT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1324             : //{
    1325             : //    uint32_t dst(optimize->f_indexes[0]),
    1326             : //             divisor(optimize->f_indexes[2]);
    1327             : //
    1328             : //    int32_t  dividend(static_cast<int16_t>(optimize->f_indexes[1]));
    1329             : //
    1330             : //    double value(divisor == 0 ? NAN : static_cast<double>(dividend) / static_cast<double>(divisor));
    1331             : //
    1332             : //    Float64 v(node_array[dst]->get_float64());
    1333             : //    v.set(value);
    1334             : //    node_array[dst]->set_float64(v);
    1335             : //}
    1336             : 
    1337             : 
    1338             : /** \brief Apply a SET_INTEGER function.
    1339             :  *
    1340             :  * This function sets the value of an integer node. This is used when
    1341             :  * an optimization can determine the result of a numeric expression and
    1342             :  * a simple integer can be set as the result.
    1343             :  *
    1344             :  * For example, a bitwise operation with NaN returns zero. This
    1345             :  * function can be used for that purpose.
    1346             :  *
    1347             :  * \li 0 -- node to be modified, it must be a NODE_INT64
    1348             :  * \li 1 -- new value (taken as a signed 16 bit value)
    1349             :  *
    1350             :  * Note that at this point this function limits the value to 16 bits.
    1351             :  *
    1352             :  * \param[in] node_array  The array of nodes being optimized.
    1353             :  * \param[in] optimize  The optimization parameters.
    1354             :  */
    1355          12 : void optimizer_func_SET_INTEGER(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1356             : {
    1357          12 :     uint32_t dst(optimize->f_indexes[0]);
    1358             : 
    1359          12 :     int32_t  value(static_cast<int16_t>(optimize->f_indexes[1]));
    1360             : 
    1361          12 :     Int64 v(node_array[dst]->get_int64());
    1362          12 :     v.set(value);
    1363          12 :     node_array[dst]->set_int64(v);
    1364          12 : }
    1365             : 
    1366             : 
    1367             : /** \brief Apply a SET_NODE_TYPE function.
    1368             :  *
    1369             :  * This function changes a node with another one. For example, it changes
    1370             :  * the NODE_ASSIGNMENT_SUBTRACT to a NODE_ASSIGNMENT when the subtract is
    1371             :  * useless (i.e. the right handside is NaN.)
    1372             :  *
    1373             :  * \li 0 -- the new node type (Node::node_t::NODE_...)
    1374             :  * \li 1 -- the offset of the node to be replaced
    1375             :  *
    1376             :  * \param[in] node_array  The array of nodes being optimized.
    1377             :  * \param[in] optimize  The optimization parameters.
    1378             :  */
    1379          21 : void optimizer_func_SET_NODE_TYPE(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1380             : {
    1381          21 :     Node::node_t node_type(static_cast<Node::node_t>(optimize->f_indexes[0]));
    1382          21 :     uint32_t src(optimize->f_indexes[1]);
    1383             : 
    1384          21 :     Node::pointer_t node(new Node(node_type));
    1385             : 
    1386          42 :     Node::pointer_t to_replace(node_array[src]);
    1387             : 
    1388          21 :     size_t max_children(to_replace->get_children_size());
    1389          63 :     for(size_t idx(0); idx < max_children; ++idx)
    1390             :     {
    1391          42 :         node->append_child(to_replace->get_child(0));
    1392             :     }
    1393          21 :     to_replace->replace_with(node);
    1394          42 :     node_array[src] = node;
    1395          21 : }
    1396             : 
    1397             : 
    1398             : /** \brief Apply an SHIFT_LEFT function.
    1399             :  *
    1400             :  * This function shifts the first number to the left by the number of bits
    1401             :  * indicated by the second number and saves the result in the 3rd position.
    1402             :  *
    1403             :  * \li 0 -- source 1
    1404             :  * \li 1 -- source 2
    1405             :  * \li 2 -- destination
    1406             :  *
    1407             :  * Although the shift left could be computed using 64 bits when handling
    1408             :  * integer we do 32 bits to make sure that we get a result as
    1409             :  * JavaScript would.
    1410             :  *
    1411             :  * \exception exception_internal_error
    1412             :  * The function attempts to convert the input to itneger numbers.
    1413             :  * If that fails, this exception is raised. The Optimizer matching
    1414             :  * mechanism should, however, prevent all such problems.
    1415             :  *
    1416             :  * \param[in] node_array  The array of nodes being optimized.
    1417             :  * \param[in] optimize  The optimization parameters.
    1418             :  */
    1419           3 : void optimizer_func_SHIFT_LEFT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1420             : {
    1421           3 :     uint32_t src1(optimize->f_indexes[0]),
    1422           3 :              src2(optimize->f_indexes[1]),
    1423           3 :              dst(optimize->f_indexes[2]);
    1424             : 
    1425           6 :     if(!node_array[src1]->to_int64()
    1426           3 :     || !node_array[src2]->to_int64())
    1427             :     {
    1428             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
    1429             :     }
    1430             : 
    1431             :     // compute the result
    1432             :     // a << b
    1433           3 :     Int64 i1(node_array[src1]->get_int64());
    1434           3 :     Int64 i2(node_array[src2]->get_int64());
    1435             :     // TODO: add a test to warn about 'b' being negative or larger than 31
    1436           3 :     Int64::int64_type v2(i2.get());
    1437           3 :     Int64::int64_type v2_and(v2 & 0x1F);
    1438           3 :     if(v2 < 0)
    1439             :     {
    1440           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1441           1 :         msg << "this static shift amount is less than zero. " << v2_and << " will be used instead of " << v2 << ".";
    1442             :     }
    1443           2 :     else if(v2 >= 32)
    1444             :     {
    1445           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1446           1 :         msg << "this static shift amount is larger than 31. " << v2_and << " will be used instead of " << v2 << ".";
    1447             :     }
    1448             :     // TODO: warn about v1 being larger than 32 bits?
    1449           3 :     i1.set((i1.get() << v2_and) & 0xFFFFFFFF);
    1450           3 :     node_array[src1]->set_int64(i1);
    1451             : 
    1452             :     // save the result replacing the destination as specified
    1453           3 :     node_array[dst]->replace_with(node_array[src1]);
    1454           3 :     node_array[dst] = node_array[src1];
    1455           3 : }
    1456             : 
    1457             : 
    1458             : /** \brief Apply an SHIFT_RIGHT function.
    1459             :  *
    1460             :  * This function shifts the first number to the right by the number of bits
    1461             :  * indicated by the second number and saves the result in the 3rd position.
    1462             :  *
    1463             :  * \li 0 -- source 1
    1464             :  * \li 1 -- source 2
    1465             :  * \li 2 -- destination
    1466             :  *
    1467             :  * Although the shift right could be computed using 64 bits when handling
    1468             :  * integer we do 32 bits to make sure that we get a result as
    1469             :  * JavaScript would.
    1470             :  *
    1471             :  * \exception exception_internal_error
    1472             :  * The function attempts to convert the input to integer point numbers.
    1473             :  * If that fails, this exception is raised. The Optimizer matching
    1474             :  * mechanism should, however, prevent all such problems.
    1475             :  *
    1476             :  * \param[in] node_array  The array of nodes being optimized.
    1477             :  * \param[in] optimize  The optimization parameters.
    1478             :  */
    1479           4 : void optimizer_func_SHIFT_RIGHT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1480             : {
    1481           4 :     uint32_t src1(optimize->f_indexes[0]),
    1482           4 :              src2(optimize->f_indexes[1]),
    1483           4 :              dst(optimize->f_indexes[2]);
    1484             : 
    1485           8 :     if(!node_array[src1]->to_int64()
    1486           4 :     || !node_array[src2]->to_int64())
    1487             :     {
    1488             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
    1489             :     }
    1490             : 
    1491             :     // compute the result
    1492             :     // a >> b
    1493           4 :     Int64 i1(node_array[src1]->get_int64());
    1494           4 :     Int64 i2(node_array[src2]->get_int64());
    1495           4 :     Int64::int64_type v2(i2.get());
    1496           4 :     Int64::int64_type v2_and(v2 & 0x1F);
    1497           4 :     if(v2 < 0)
    1498             :     {
    1499           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1500           1 :         msg << "this static shift amount is less than zero. " << v2_and << " will be used instead of " << v2 << ".";
    1501             :     }
    1502           3 :     else if(v2 >= 32)
    1503             :     {
    1504           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1505           1 :         msg << "this static shift amount is larger than 31. " << v2_and << " will be used instead of " << v2 << ".";
    1506             :     }
    1507             :     // TODO: warn about v1 being larger than 32 bits?
    1508           4 :     int32_t v1(i1.get());
    1509           4 :     v1 >>= v2_and;
    1510           4 :     i1.set(v1);
    1511           4 :     node_array[src1]->set_int64(i1);
    1512             : 
    1513             :     // save the result replacing the destination as specified
    1514           4 :     node_array[dst]->replace_with(node_array[src1]);
    1515           4 :     node_array[dst] = node_array[src1];
    1516           4 : }
    1517             : 
    1518             : 
    1519             : /** \brief Apply an SHIFT_RIGHT_UNSIGNED function.
    1520             :  *
    1521             :  * This function shifts the first number to the right by the number of bits
    1522             :  * indicated by the second number and saves the result in the 3rd position.
    1523             :  *
    1524             :  * \li 0 -- source 1
    1525             :  * \li 1 -- source 2
    1526             :  * \li 2 -- destination
    1527             :  *
    1528             :  * Although the shift right could be computed using 64 bits when handling
    1529             :  * integer we do 32 bits to make sure that we get a result as
    1530             :  * JavaScript would.
    1531             :  *
    1532             :  * \exception exception_internal_error
    1533             :  * The function attempts to convert the input to integer numbers.
    1534             :  * If that fails, this exception is raised. The Optimizer matching
    1535             :  * mechanism should, however, prevent all such problems.
    1536             :  *
    1537             :  * \param[in] node_array  The array of nodes being optimized.
    1538             :  * \param[in] optimize  The optimization parameters.
    1539             :  */
    1540           4 : void optimizer_func_SHIFT_RIGHT_UNSIGNED(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1541             : {
    1542           4 :     uint32_t src1(optimize->f_indexes[0]),
    1543           4 :              src2(optimize->f_indexes[1]),
    1544           4 :              dst(optimize->f_indexes[2]);
    1545             : 
    1546           8 :     if(!node_array[src1]->to_int64()
    1547           4 :     || !node_array[src2]->to_int64())
    1548             :     {
    1549             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an int64."); // LCOV_EXCL_LINE
    1550             :     }
    1551             : 
    1552             :     // compute the result
    1553             :     // a >>> b
    1554           4 :     Int64 i1(node_array[src1]->get_int64());
    1555           4 :     Int64 i2(node_array[src2]->get_int64());
    1556           4 :     Int64::int64_type v2(i2.get());
    1557           4 :     Int64::int64_type v2_and(v2 & 0x1F);
    1558           4 :     if(v2 < 0)
    1559             :     {
    1560           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1561           1 :         msg << "this static shift amount is less than zero. " << v2_and << " will be used instead of " << v2 << ".";
    1562             :     }
    1563           3 :     else if(v2 >= 32)
    1564             :     {
    1565           1 :         Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_INVALID_NUMBER, node_array[src2]->get_position());
    1566           1 :         msg << "this static shift amount is larger than 31. " << v2_and << " will be used instead of " << v2 << ".";
    1567             :     }
    1568             :     // TODO: warn about v1 being larger than 32 bits?
    1569           4 :     uint32_t v1(i1.get());
    1570           4 :     v1 >>= v2_and;
    1571           4 :     i1.set(v1);
    1572           4 :     node_array[src1]->set_int64(i1);
    1573             : 
    1574             :     // save the result replacing the destination as specified
    1575           4 :     node_array[dst]->replace_with(node_array[src1]);
    1576           4 :     node_array[dst] = node_array[src1];
    1577           4 : }
    1578             : 
    1579             : 
    1580             : /** \brief Apply an SMART_MATCH function.
    1581             :  *
    1582             :  * This function checks source 1 against source 2. String parameters
    1583             :  * first get simplified, then the function applies the EQUAL operator
    1584             :  * against both resulting values.
    1585             :  *
    1586             :  * \li 0 -- source 1
    1587             :  * \li 1 -- source 2
    1588             :  * \li 2 -- destination
    1589             :  *
    1590             :  * \param[in] node_array  The array of nodes being optimized.
    1591             :  * \param[in] optimize  The optimization parameters.
    1592             :  */
    1593          22 : void optimizer_func_SMART_MATCH(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1594             : {
    1595          22 :     uint32_t src1(optimize->f_indexes[0]),
    1596          22 :              src2(optimize->f_indexes[1]),
    1597          22 :              dst(optimize->f_indexes[2]);
    1598             : 
    1599          22 :     Node::pointer_t s1(node_array[src1]);
    1600          44 :     Node::pointer_t s2(node_array[src2]);
    1601             : 
    1602          22 :     if(s1->get_type() == Node::node_t::NODE_STRING)
    1603             :     {
    1604           8 :         s1.reset(new Node(Node::node_t::NODE_STRING));
    1605           8 :         s1->set_string(node_array[src1]->get_string().simplified());
    1606             :     }
    1607             : 
    1608          22 :     if(s2->get_type() == Node::node_t::NODE_STRING)
    1609             :     {
    1610           7 :         s2.reset(new Node(Node::node_t::NODE_STRING));
    1611           7 :         s2->set_string(node_array[src2]->get_string().simplified());
    1612             :     }
    1613             : 
    1614          22 :     compare_t const c(Node::compare(s1, s2, Node::compare_mode_t::COMPARE_SMART));
    1615             :     Node::pointer_t result(new Node(c == compare_t::COMPARE_EQUAL
    1616             :                                     ? Node::node_t::NODE_TRUE
    1617          44 :                                     : Node::node_t::NODE_FALSE));
    1618             : 
    1619             :     // save the result replacing the destination as specified
    1620          22 :     node_array[dst]->replace_with(result);
    1621          44 :     node_array[dst] = result;
    1622          22 : }
    1623             : 
    1624             : 
    1625             : /** \brief Apply an STRICTLY_EQUAL function.
    1626             :  *
    1627             :  * This function checks source 1 against source 2. If source 1 is equal to
    1628             :  * source 2, then the function saves true in the destination, otherwise
    1629             :  * it saves false.
    1630             :  *
    1631             :  * \li 0 -- source 1
    1632             :  * \li 1 -- source 2
    1633             :  * \li 2 -- destination
    1634             :  *
    1635             :  * \param[in] node_array  The array of nodes being optimized.
    1636             :  * \param[in] optimize  The optimization parameters.
    1637             :  */
    1638          40 : void optimizer_func_STRICTLY_EQUAL(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1639             : {
    1640          40 :     uint32_t src1(optimize->f_indexes[0]),
    1641          40 :              src2(optimize->f_indexes[1]),
    1642          40 :              dst(optimize->f_indexes[2]);
    1643             : 
    1644          40 :     compare_t const c(Node::compare(node_array[src1], node_array[src2], Node::compare_mode_t::COMPARE_STRICT));
    1645             :     Node::pointer_t result(new Node(c == compare_t::COMPARE_EQUAL
    1646             :                                     ? Node::node_t::NODE_TRUE
    1647          40 :                                     : Node::node_t::NODE_FALSE));
    1648             : 
    1649             :     // save the result replacing the destination as specified
    1650          40 :     node_array[dst]->replace_with(result);
    1651          40 :     node_array[dst] = result;
    1652          40 : }
    1653             : 
    1654             : 
    1655             : /** \brief Apply an SUBTRACT function.
    1656             :  *
    1657             :  * This function adds two numbers and saves the result in the 3rd position.
    1658             :  *
    1659             :  * \li 0 -- source 1
    1660             :  * \li 1 -- source 2
    1661             :  * \li 2 -- destination
    1662             :  *
    1663             :  * \exception exception_internal_error
    1664             :  * The function may attempt to convert the input to floating point numbers.
    1665             :  * If that fails, this exception is raised. The Optimizer matching mechanism
    1666             :  * should, however, prevent all such problems.
    1667             :  *
    1668             :  * \param[in] node_array  The array of nodes being optimized.
    1669             :  * \param[in] optimize  The optimization parameters.
    1670             :  */
    1671           4 : void optimizer_func_SUBTRACT(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1672             : {
    1673           4 :     uint32_t src1(optimize->f_indexes[0]),
    1674           4 :              src2(optimize->f_indexes[1]),
    1675           4 :              dst(optimize->f_indexes[2]);
    1676             : 
    1677           4 :     Node::node_t type1(node_array[src1]->get_type());
    1678           4 :     Node::node_t type2(node_array[src2]->get_type());
    1679             : 
    1680             :     // add the numbers together
    1681           4 :     if(type1 == Node::node_t::NODE_INT64 && type2 == Node::node_t::NODE_INT64)
    1682             :     {
    1683             :         // a - b when a and b are integers
    1684           1 :         Int64 i1(node_array[src1]->get_int64());
    1685           1 :         Int64 i2(node_array[src2]->get_int64());
    1686             :         // TODO: err on overflows?
    1687           1 :         i1.set(i1.get() - i2.get());
    1688           1 :         node_array[src1]->set_int64(i1);
    1689             :     }
    1690             :     else
    1691             :     {
    1692             :         // make sure a and b are floats, then do a - b as floats
    1693             :         // TODO: check for NaN and other fun things?
    1694           6 :         if(!node_array[src1]->to_float64()
    1695           3 :         || !node_array[src2]->to_float64())
    1696             :         {
    1697             :             throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a float64."); // LCOV_EXCL_LINE
    1698             :         }
    1699           3 :         Float64 f1(node_array[src1]->get_float64());
    1700           3 :         Float64 f2(node_array[src2]->get_float64());
    1701             :         // TODO: err on overflow?
    1702           3 :         f1.set(f1.get() - f2.get());
    1703           3 :         node_array[src1]->set_float64(f1);
    1704             :     }
    1705             : 
    1706             :     // save the result replacing the destination as specified
    1707           4 :     node_array[dst]->replace_with(node_array[src1]);
    1708           4 :     node_array[dst] = node_array[src1];
    1709           4 : }
    1710             : 
    1711             : 
    1712             : /** \brief Apply a SWAP function.
    1713             :  *
    1714             :  * This function exchanges a node with another. For example, we can inverse
    1715             :  * a condition in an 'if()' statement and then swap the first list of
    1716             :  * statements with the second (i.e. the 'then' part with the 'else' part.)
    1717             :  *
    1718             :  * \li 0 -- source 1
    1719             :  * \li 1 -- source 2
    1720             :  *
    1721             :  * \param[in] node_array  The array of nodes being optimized.
    1722             :  * \param[in] optimize  The optimization parameters.
    1723             :  */
    1724           1 : void optimizer_func_SWAP(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1725             : {
    1726           1 :     uint32_t src1(optimize->f_indexes[0]),
    1727           1 :              src2(optimize->f_indexes[1]);
    1728             : 
    1729             :     // get the existing pointers and offsets
    1730           1 :     Node::pointer_t n1(node_array[src1]);
    1731           2 :     Node::pointer_t n2(node_array[src2]);
    1732             : 
    1733           2 :     Node::pointer_t p1(n1->get_parent());
    1734           2 :     Node::pointer_t p2(n2->get_parent());
    1735             : 
    1736           2 :     Node::pointer_t e1(new Node(Node::node_t::NODE_EMPTY));
    1737           2 :     Node::pointer_t e2(new Node(Node::node_t::NODE_EMPTY));
    1738             : 
    1739           1 :     size_t o1(n1->get_offset());
    1740           1 :     size_t o2(n2->get_offset());
    1741             : 
    1742           1 :     p1->set_child(o1, e1);
    1743           1 :     p2->set_child(o2, e2);
    1744             : 
    1745           1 :     p1->set_child(o1, n2);
    1746           1 :     p2->set_child(o2, n1);
    1747             : 
    1748           1 :     node_array[src1] = n2;
    1749           2 :     node_array[src2] = n1;
    1750             : 
    1751             :     // WARNING: we do not use the replace_with() function because we would
    1752             :     //          otherwise lose the parent and offset information
    1753           1 : }
    1754             : 
    1755             : 
    1756             : /** \brief Apply an TO_CONDITIONAL function.
    1757             :  *
    1758             :  * This function replaces a number with a conditional.
    1759             :  *
    1760             :  * \li 0 -- source 1 (true/false expression)
    1761             :  * \li 1 -- source 2 (result if true)
    1762             :  * \li 2 -- source 3 (result if false)
    1763             :  * \li 3 -- destination (destination)
    1764             :  *
    1765             :  * \exception exception_internal_error
    1766             :  * The function may attempt to convert the input to floating point numbers.
    1767             :  * If that fails, this exception is raised. The Optimizer matching mechanism
    1768             :  * should, however, prevent all such problems.
    1769             :  *
    1770             :  * \param[in] node_array  The array of nodes being optimized.
    1771             :  * \param[in] optimize  The optimization parameters.
    1772             :  */
    1773           1 : void optimizer_func_TO_CONDITIONAL(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1774             : {
    1775           1 :     uint32_t src1(optimize->f_indexes[0]),
    1776           1 :              src2(optimize->f_indexes[1]),
    1777           1 :              src3(optimize->f_indexes[2]),
    1778           1 :              dst(optimize->f_indexes[3]);
    1779             : 
    1780           1 :     Node::pointer_t conditional(new Node(Node::node_t::NODE_CONDITIONAL));
    1781           1 :     conditional->append_child(node_array[src1]);
    1782           1 :     conditional->append_child(node_array[src2]);
    1783           1 :     conditional->append_child(node_array[src3]);
    1784             : 
    1785             :     // save the result replacing the specified destination
    1786           1 :     node_array[dst]->replace_with(conditional);
    1787           1 :     node_array[dst] = conditional;
    1788           1 : }
    1789             : 
    1790             : 
    1791             : ///** \brief Apply a TO_FLOAT64 function.
    1792             : // *
    1793             : // * This function transforms a node to a floating point number. The
    1794             : // * to_float64() HAS to work against that node or you will get an
    1795             : // * exception.
    1796             : // *
    1797             : // * \exception exception_internal_error
    1798             : // * The function attempts to convert the input to a floating point number.
    1799             : // * If that fails, this exception is raised. The Optimizer matching mechanism
    1800             : // * should, however, prevent all such problems.
    1801             : // *
    1802             : // * \param[in] node_array  The array of nodes being optimized.
    1803             : // * \param[in] optimize  The optimization parameters.
    1804             : // */
    1805             : //void optimizer_func_TO_FLOAT64(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1806             : //{
    1807             : //    if(!node_array[optimize->f_indexes[0]]->to_float64())
    1808             : //    {
    1809             : //        throw exception_internal_error("optimizer used function to_float64() against a node that cannot be converted to a floating point number."); // LCOV_EXCL_LINE
    1810             : //    }
    1811             : //}
    1812             : 
    1813             : 
    1814             : /** \brief Apply a TO_INT64 function.
    1815             :  *
    1816             :  * This function transforms a node to an integer number. The
    1817             :  * to_int64() HAS to work against that node or you will get an
    1818             :  * exception.
    1819             :  *
    1820             :  * \exception exception_internal_error
    1821             :  * The function attempts to convert the input to an integer number.
    1822             :  * If that fails, this exception is raised. The Optimizer matching mechanism
    1823             :  * should, however, prevent all such problems.
    1824             :  *
    1825             :  * \param[in] node_array  The array of nodes being optimized.
    1826             :  * \param[in] optimize  The optimization parameters.
    1827             :  */
    1828          12 : void optimizer_func_TO_INT64(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1829             : {
    1830          12 :     if(!node_array[optimize->f_indexes[0]]->to_int64())
    1831             :     {
    1832             :         throw exception_internal_error("optimizer used function to_int64() against a node that cannot be converted to an integer."); // LCOV_EXCL_LINE
    1833             :     }
    1834          12 : }
    1835             : 
    1836             : 
    1837             : /** \brief Apply a TO_NUMBER function.
    1838             :  *
    1839             :  * This function transforms a node to a number. The
    1840             :  * to_number() HAS to work against that node or you will get an
    1841             :  * exception.
    1842             :  *
    1843             :  * \exception exception_internal_error
    1844             :  * The function attempts to convert the input to an integer number.
    1845             :  * If that fails, this exception is raised. The Optimizer matching mechanism
    1846             :  * should, however, prevent all such problems.
    1847             :  *
    1848             :  * \param[in] node_array  The array of nodes being optimized.
    1849             :  * \param[in] optimize  The optimization parameters.
    1850             :  */
    1851          53 : void optimizer_func_TO_NUMBER(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1852             : {
    1853          53 :     if(!node_array[optimize->f_indexes[0]]->to_number())
    1854             :     {
    1855             :         throw exception_internal_error("optimizer used function to_number() against a node that cannot be converted to a number."); // LCOV_EXCL_LINE
    1856             :     }
    1857          53 : }
    1858             : 
    1859             : 
    1860             : ///** \brief Apply a TO_STRING function.
    1861             : // *
    1862             : // * This function transforms a node to a string. The to_string() HAS to work
    1863             : // * against that node or you will get an exception.
    1864             : // *
    1865             : // * \exception exception_internal_error
    1866             : // * The function attempts to convert the input to a string.
    1867             : // * If that fails, this exception is raised. The Optimizer matching mechanism
    1868             : // * should, however, prevent all such problems.
    1869             : // *
    1870             : // * \param[in] node_array  The array of nodes being optimized.
    1871             : // * \param[in] optimize  The optimization parameters.
    1872             : // */
    1873             : //void optimizer_func_TO_STRING(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1874             : //{
    1875             : //    if(!node_array[optimize->f_indexes[0]]->to_string())
    1876             : //    {
    1877             : //        throw exception_internal_error("optimizer used function to_string() against a node that cannot be converted to a string."); // LCOV_EXCL_LINE
    1878             : //    }
    1879             : //}
    1880             : 
    1881             : 
    1882             : /** \brief Apply a WHILE_TRUE_TO_FOREVER function.
    1883             :  *
    1884             :  * This function transforms a 'while(true)' in a 'for(;;)' which is a bit
    1885             :  * smaller.
    1886             :  *
    1887             :  * \param[in] node_array  The array of nodes being optimized.
    1888             :  * \param[in] optimize  The optimization parameters.
    1889             :  */
    1890           2 : void optimizer_func_WHILE_TRUE_TO_FOREVER(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    1891             : {
    1892           2 :     uint32_t src(optimize->f_indexes[0]),
    1893           2 :              dst(optimize->f_indexes[1]);
    1894             : 
    1895           2 :     Node::pointer_t statements(node_array[src]);
    1896           4 :     Node::pointer_t for_statement(new Node(Node::node_t::NODE_FOR));
    1897           4 :     Node::pointer_t e1(new Node(Node::node_t::NODE_EMPTY));
    1898           4 :     Node::pointer_t e2(new Node(Node::node_t::NODE_EMPTY));
    1899           4 :     Node::pointer_t e3(new Node(Node::node_t::NODE_EMPTY));
    1900             : 
    1901           2 :     node_array[dst]->replace_with(for_statement);
    1902           2 :     node_array[dst] = for_statement;
    1903           2 :     for_statement->append_child(e1);
    1904           2 :     for_statement->append_child(e2);
    1905           2 :     for_statement->append_child(e3);
    1906           4 :     for_statement->append_child(statements);
    1907           2 : }
    1908             : 
    1909             : 
    1910             : /** \brief Internal structure used to define a list of optimization functions.
    1911             :  *
    1912             :  * This structure is used to define a list of optimization functions which
    1913             :  * are used to optimize the tree of nodes.
    1914             :  *
    1915             :  * In debug mode, we add the function index so we can make sure that the
    1916             :  * functions are properly sorted and are all defined. (At least we try, we
    1917             :  * cannot detect whether the last function is defined because we do not
    1918             :  * have a "max" definition.)
    1919             :  */
    1920             : struct optimizer_optimize_function_t
    1921             : {
    1922             : #if defined(_DEBUG) || defined(DEBUG)
    1923             :     /** \brief The function index.
    1924             :      *
    1925             :      * This entry is only added in case the software is compiled in debug
    1926             :      * mode. It allows our functions to verify that all the functions are
    1927             :      * defined as required.
    1928             :      *
    1929             :      * In non-debug, the functions make use of the table as is, expecting
    1930             :      * it to be proper (which it should be if our tests do their job
    1931             :      * properly.)
    1932             :      */
    1933             :     optimization_function_t     f_func_index;
    1934             : #endif
    1935             : 
    1936             :     /** \brief The function pointer.
    1937             :      *
    1938             :      * When executing the different optimization functions, we call them
    1939             :      * using this table. This is faster than using a switch, a much less
    1940             :      * prone to errors since the function index and the function names
    1941             :      * are tied together.
    1942             :      *
    1943             :      * \param[in] node_array  The array of nodes being optimized.
    1944             :      * \param[in] optimize  The optimization parameters.
    1945             :      */
    1946             :     void                        (*f_func)(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize);
    1947             : };
    1948             : 
    1949             : 
    1950             : #if defined(_DEBUG) || defined(DEBUG)
    1951             : #define OPTIMIZER_FUNC(name) { optimization_function_t::OPTIMIZATION_FUNCTION_##name, optimizer_func_##name }
    1952             : #else
    1953             : #define OPTIMIZER_FUNC(name) { optimizer_func_##name }
    1954             : #endif
    1955             : 
    1956             : /** \brief List of optimization functions.
    1957             :  *
    1958             :  * This table is a list of optimization functions called using
    1959             :  * optimizer_apply_funtion().
    1960             :  */
    1961             : optimizer_optimize_function_t g_optimizer_optimize_functions[] =
    1962             : {
    1963             :     /* OPTIMIZATION_FUNCTION_ADD            */ OPTIMIZER_FUNC(ADD),
    1964             :     /* OPTIMIZATION_FUNCTION_BITWISE_AND    */ OPTIMIZER_FUNC(BITWISE_AND),
    1965             :     /* OPTIMIZATION_FUNCTION_BITWISE_NOT    */ OPTIMIZER_FUNC(BITWISE_NOT),
    1966             :     /* OPTIMIZATION_FUNCTION_BITWISE_OR     */ OPTIMIZER_FUNC(BITWISE_OR),
    1967             :     /* OPTIMIZATION_FUNCTION_BITWISE_XOR    */ OPTIMIZER_FUNC(BITWISE_XOR),
    1968             :     /* OPTIMIZATION_FUNCTION_COMPARE        */ OPTIMIZER_FUNC(COMPARE),
    1969             :     /* OPTIMIZATION_FUNCTION_CONCATENATE    */ OPTIMIZER_FUNC(CONCATENATE),
    1970             :     /* OPTIMIZATION_FUNCTION_DIVIDE         */ OPTIMIZER_FUNC(DIVIDE),
    1971             :     /* OPTIMIZATION_FUNCTION_EQUAL          */ OPTIMIZER_FUNC(EQUAL),
    1972             :     /* OPTIMIZATION_FUNCTION_LESS           */ OPTIMIZER_FUNC(LESS),
    1973             :     /* OPTIMIZATION_FUNCTION_LESS_EQUAL     */ OPTIMIZER_FUNC(LESS_EQUAL),
    1974             :     /* OPTIMIZATION_FUNCTION_LOGICAL_NOT    */ OPTIMIZER_FUNC(LOGICAL_NOT),
    1975             :     /* OPTIMIZATION_FUNCTION_LOGICAL_XOR    */ OPTIMIZER_FUNC(LOGICAL_XOR),
    1976             :     /* OPTIMIZATION_FUNCTION_MATCH          */ OPTIMIZER_FUNC(MATCH),
    1977             :     /* OPTIMIZATION_FUNCTION_MAXIMUM        */ OPTIMIZER_FUNC(MAXIMUM),
    1978             :     /* OPTIMIZATION_FUNCTION_MINIMUM        */ OPTIMIZER_FUNC(MINIMUM),
    1979             :     /* OPTIMIZATION_FUNCTION_MODULO         */ OPTIMIZER_FUNC(MODULO),
    1980             :     /* OPTIMIZATION_FUNCTION_MOVE           */ OPTIMIZER_FUNC(MOVE),
    1981             :     /* OPTIMIZATION_FUNCTION_MULTIPLY       */ OPTIMIZER_FUNC(MULTIPLY),
    1982             :     /* OPTIMIZATION_FUNCTION_NEGATE         */ OPTIMIZER_FUNC(NEGATE),
    1983             :     /* OPTIMIZATION_FUNCTION_POWER          */ OPTIMIZER_FUNC(POWER),
    1984             :     /* OPTIMIZATION_FUNCTION_REMOVE         */ OPTIMIZER_FUNC(REMOVE),
    1985             :     /* OPTIMIZATION_FUNCTION_ROTATE_LEFT    */ OPTIMIZER_FUNC(ROTATE_LEFT),
    1986             :     /* OPTIMIZATION_FUNCTION_ROTATE_RIGHT   */ OPTIMIZER_FUNC(ROTATE_RIGHT),
    1987             :     /* OPTIMIZATION_FUNCTION_SET_INTEGER    */ OPTIMIZER_FUNC(SET_INTEGER),
    1988             :     ///* OPTIMIZATION_FUNCTION_SET_FLOAT      */ OPTIMIZER_FUNC(SET_FLOAT),
    1989             :     /* OPTIMIZATION_FUNCTION_SET_NODE_TYPE  */ OPTIMIZER_FUNC(SET_NODE_TYPE),
    1990             :     /* OPTIMIZATION_FUNCTION_SHIFT_LEFT     */ OPTIMIZER_FUNC(SHIFT_LEFT),
    1991             :     /* OPTIMIZATION_FUNCTION_SHIFT_RIGHT    */ OPTIMIZER_FUNC(SHIFT_RIGHT),
    1992             :     /* OPTIMIZATION_FUNCTION_SHIFT_RIGHT_UNSIGNED */ OPTIMIZER_FUNC(SHIFT_RIGHT_UNSIGNED),
    1993             :     /* OPTIMIZATION_FUNCTION_SMART_MATCH    */ OPTIMIZER_FUNC(SMART_MATCH),
    1994             :     /* OPTIMIZATION_FUNCTION_STRICTLY_EQUAL */ OPTIMIZER_FUNC(STRICTLY_EQUAL),
    1995             :     /* OPTIMIZATION_FUNCTION_SUBTRACT       */ OPTIMIZER_FUNC(SUBTRACT),
    1996             :     /* OPTIMIZATION_FUNCTION_SWAP           */ OPTIMIZER_FUNC(SWAP),
    1997             :     /* OPTIMIZATION_FUNCTION_TO_CONDITIONAL */ OPTIMIZER_FUNC(TO_CONDITIONAL),
    1998             :     ///* OPTIMIZATION_FUNCTION_TO_FLOAT64     */ OPTIMIZER_FUNC(TO_FLOAT64),
    1999             :     /* OPTIMIZATION_FUNCTION_TO_INT64       */ OPTIMIZER_FUNC(TO_INT64),
    2000             :     /* OPTIMIZATION_FUNCTION_TO_NUMBER      */ OPTIMIZER_FUNC(TO_NUMBER),
    2001             :     ///* OPTIMIZATION_FUNCTION_TO_STRING      */ OPTIMIZER_FUNC(TO_STRING),
    2002             :     /* OPTIMIZATION_FUNCTION_WHILE_TRUE_TO_FOREVER */ OPTIMIZER_FUNC(WHILE_TRUE_TO_FOREVER)
    2003             : };
    2004             : 
    2005             : /** \brief The size of the optimizer list of optimization functions.
    2006             :  *
    2007             :  * This size defines the number of functions available in the optimizer
    2008             :  * optimize functions table. This size should be equal to the last
    2009             :  * optimization function number plus one. This is tested in
    2010             :  * optimizer_apply_function() when in debug mode.
    2011             :  */
    2012             : size_t const g_optimizer_optimize_functions_size = sizeof(g_optimizer_optimize_functions) / sizeof(g_optimizer_optimize_functions[0]);
    2013             : 
    2014             : 
    2015             : /** \brief Apply optimization functions to a node.
    2016             :  *
    2017             :  * This function applies one optimization function to a node. In many
    2018             :  * cases, the node itself gets replaced by a child.
    2019             :  *
    2020             :  * In debug mode the function may raise an exception if a bug is detected
    2021             :  * in the table data.
    2022             :  *
    2023             :  * \param[in] node  The node being optimized.
    2024             :  * \param[in] optimize  The optimization function to apply.
    2025             :  */
    2026         646 : void apply_one_function(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize)
    2027             : {
    2028             : #if defined(_DEBUG) || defined(DEBUG)
    2029             :     // this loop will not catch the last entries if missing, otherwise,
    2030             :     // 'internal' functions are detected immediately, hence our other
    2031             :     // test below
    2032       24548 :     for(size_t idx(0); idx < g_optimizer_optimize_functions_size; ++idx)
    2033             :     {
    2034       23902 :         if(g_optimizer_optimize_functions[idx].f_func_index != static_cast<optimization_function_t>(idx))
    2035             :         {
    2036             :             std::cerr << "INTERNAL ERROR: function table index " << idx << " is not valid."            // LCOV_EXCL_LINE
    2037             :                       << std::endl;                                                                    // LCOV_EXCL_LINE
    2038             :             throw exception_internal_error("INTERNAL ERROR: function table index is not valid (forgot to add a function to the table?)"); // LCOV_EXCL_LINE
    2039             :         }
    2040             :     }
    2041             :     // make sure the function exists, otherwise we'd just crash (not good!)
    2042         646 :     if(static_cast<size_t>(optimize->f_function) >= g_optimizer_optimize_functions_size)
    2043             :     {
    2044             :         std::cerr << "INTERNAL ERROR: f_function is too large " << static_cast<int>(optimize->f_function) << " > "      // LCOV_EXCL_LINE
    2045             :                   << sizeof(g_optimizer_optimize_functions) / sizeof(g_optimizer_optimize_functions[0])                 // LCOV_EXCL_LINE
    2046             :                   << std::endl;                                                                                         // LCOV_EXCL_LINE
    2047             :         throw exception_internal_error("INTERNAL ERROR: f_function is out of range (forgot to add a function to the table?)"); // LCOV_EXCL_LINE
    2048             :     }
    2049             : #endif
    2050         646 :     g_optimizer_optimize_functions[static_cast<size_t>(optimize->f_function)].f_func(node_array, optimize);
    2051         646 : }
    2052             : 
    2053             : 
    2054             : }
    2055             : // noname namespace
    2056             : 
    2057             : 
    2058             : /** \brief Apply all the optimization functions.
    2059             :  *
    2060             :  * This function applies all the optimization functions on the specified
    2061             :  * array of nodes one after the other.
    2062             :  *
    2063             :  * If a parameter (node) is invalid for a function, an exception is raised.
    2064             :  * Because the optimizer is expected to properly match nodes before
    2065             :  * an optimization can be applied, the possibility for an error here
    2066             :  * should be zero.
    2067             :  *
    2068             :  * \param[in] node_array  The array of nodes as generated by the matching code.
    2069             :  * \param[in] optimize  Pointer to the first optimization function.
    2070             :  * \param[in] optimize_size  The number of optimization functions to apply.
    2071             :  */
    2072         524 : void apply_functions(node_pointer_vector_t& node_array, optimization_optimize_t const *optimize, size_t optimize_size)
    2073             : {
    2074        1170 :     for(; optimize_size > 0; --optimize_size, ++optimize)
    2075             :     {
    2076         646 :         apply_one_function(node_array, optimize);
    2077             :     }
    2078         524 : }
    2079             : 
    2080             : 
    2081             : }
    2082             : // namespace optimizer_details
    2083          63 : }
    2084             : // namespace as2js
    2085             : 
    2086             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10