LCOV - code coverage report
Current view: top level - lib - node_compare.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 61 100.0 %
Date: 2014-11-22 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* node_compare.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    "as2js/node.h"
      37             : 
      38             : #include    "as2js/exceptions.h"
      39             : 
      40             : 
      41             : /** \file
      42             :  * \brief Compare two nodes against each others.
      43             :  *
      44             :  * This function is used to compare two nodes against each others. The
      45             :  * compare is expected to return a compare_t enumeration value.
      46             :  *
      47             :  * At this time, the implementation only compares basic literals (i.e.
      48             :  * integers, floating points, strings, Booleans, null, undefined.)
      49             :  *
      50             :  * \todo
      51             :  * Implement a compare of object and array literals.
      52             :  */
      53             : 
      54             : 
      55             : namespace as2js
      56             : {
      57             : 
      58             : 
      59             : 
      60             : /**********************************************************************/
      61             : /**********************************************************************/
      62             : /***  NODE COMPARE  ***************************************************/
      63             : /**********************************************************************/
      64             : /**********************************************************************/
      65             : 
      66             : 
      67             : /** \brief Compare two nodes together.
      68             :  *
      69             :  * This function returns the result of comparing two nodes against each
      70             :  * others. The result is one of the compare_t values.
      71             :  *
      72             :  * At this time, if the function is used to compare nodes that are not
      73             :  * literals, then it returns COMPARE_ERROR.
      74             :  *
      75             :  * The function may return COMPARE_UNORDERED in strict mode or when
      76             :  * comparing a value against a NaN.
      77             :  *
      78             :  * As per the ECMAScript refence, strings are compared as is in binary
      79             :  * mode. We do not make use of Unicode or take the locale in account.
      80             :  *
      81             :  * \note
      82             :  * The compare is expected to work as defined in ECMAScript 5 (see 11.8.5,
      83             :  * 11.9.3, and 11.9.6).
      84             :  *
      85             :  * The nearly equal is only used by the smart match operator. This is an
      86             :  * addition by as2js which is somewhat like the ~~ operator defined by
      87             :  * perl.
      88             :  *
      89             :  * \param[in] lhs  The left hand side node.
      90             :  * \param[in] rhs  The right hand side node.
      91             :  * \param[in] mode  Whether the compare is strict, lousy, or smart
      92             :  *                  (===, ==, ~~).
      93             :  *
      94             :  * \return One of the compare_t values representing the comparison result.
      95             :  */
      96        1563 : compare_t Node::compare(Node::pointer_t const lhs, Node::pointer_t const rhs, compare_mode_t const mode)
      97             : {
      98        1563 :     if(!lhs->is_literal() || !rhs->is_literal())
      99             :     {
     100             :         // invalid left or right hand side
     101        1141 :         return compare_t::COMPARE_ERROR;
     102             :     }
     103             : 
     104             :     // since we do not have a NODE_BOOLEAN, but instead have NODE_TRUE
     105             :     // and NODE_FALSE, we have to handle that case separately
     106         422 :     if(lhs->f_type == node_t::NODE_FALSE)
     107             :     {
     108          27 :         if(rhs->f_type == node_t::NODE_FALSE)
     109             :         {
     110          12 :             return compare_t::COMPARE_EQUAL;
     111             :         }
     112          15 :         if(rhs->f_type == node_t::NODE_TRUE)
     113             :         {
     114          12 :             return compare_t::COMPARE_LESS;
     115             :         }
     116             :     }
     117         395 :     else if(lhs->f_type == node_t::NODE_TRUE)
     118             :     {
     119          27 :         if(rhs->f_type == node_t::NODE_FALSE)
     120             :         {
     121          12 :             return compare_t::COMPARE_GREATER;
     122             :         }
     123          15 :         if(rhs->f_type == node_t::NODE_TRUE)
     124             :         {
     125          12 :             return compare_t::COMPARE_EQUAL;
     126             :         }
     127             :     }
     128             : 
     129             :     // exact same type?
     130         374 :     if(lhs->f_type == rhs->f_type)
     131             :     {
     132         213 :         switch(lhs->f_type)
     133             :         {
     134             :         case node_t::NODE_FLOAT64:
     135             :             // NaN is a special case we have to take in account
     136          88 :             if(mode == compare_mode_t::COMPARE_SMART && lhs->get_float64().nearly_equal(rhs->get_float64()))
     137             :             {
     138           7 :                 return compare_t::COMPARE_EQUAL;
     139             :             }
     140          81 :             return lhs->get_float64().compare(rhs->get_float64());
     141             : 
     142             :         case node_t::NODE_INT64:
     143          44 :             return lhs->get_int64().compare(rhs->get_int64());
     144             : 
     145             :         case node_t::NODE_NULL:
     146          12 :             return compare_t::COMPARE_EQUAL;
     147             : 
     148             :         case node_t::NODE_STRING:
     149          57 :             if(lhs->f_str == rhs->f_str)
     150             :             {
     151          19 :                 return compare_t::COMPARE_EQUAL;
     152             :             }
     153          38 :             return lhs->f_str < rhs->f_str ? compare_t::COMPARE_LESS : compare_t::COMPARE_GREATER;
     154             : 
     155             :         case node_t::NODE_UNDEFINED:
     156          12 :             return compare_t::COMPARE_EQUAL;
     157             : 
     158             :         default:
     159             :             throw exception_internal_error("INTERNAL ERROR: comparing two literal nodes with an unknown type."); // LCOV_EXCL_LINE
     160             : 
     161             :         }
     162             :         /*NOTREACHED*/
     163             :     }
     164             : 
     165             :     // if strict mode is turned on, we cannot compare objects
     166             :     // that are not of the same type (i.e. no conversions allowed)
     167         161 :     if(mode == compare_mode_t::COMPARE_STRICT)
     168             :     {
     169          42 :         return compare_t::COMPARE_UNORDERED;
     170             :     }
     171             : 
     172             :     // we handle one special case here since 'undefined' is otherwise
     173             :     // converted to NaN and it would not be equal to 'null' which is
     174             :     // represented as being equal to zero
     175         250 :     if((lhs->f_type == node_t::NODE_NULL && rhs->f_type == node_t::NODE_UNDEFINED)
     176         229 :     || (lhs->f_type == node_t::NODE_UNDEFINED && rhs->f_type == node_t::NODE_NULL))
     177             :     {
     178          17 :         return compare_t::COMPARE_EQUAL;
     179             :     }
     180             : 
     181             :     // if we are here, we have go to convert both parameters to floating
     182             :     // point numbers and compare the result (remember that we do not handle
     183             :     // objects in this functon)
     184         102 :     Float64 lf;
     185         102 :     switch(lhs->f_type)
     186             :     {
     187             :     case node_t::NODE_INT64:
     188           7 :         lf.set(lhs->f_int.get());
     189           7 :         break;
     190             : 
     191             :     case node_t::NODE_FLOAT64:
     192          46 :         lf = lhs->f_float;
     193          46 :         break;
     194             : 
     195             :     case node_t::NODE_TRUE:
     196           2 :         lf.set(1.0);
     197           2 :         break;
     198             : 
     199             :     case node_t::NODE_NULL:
     200             :     case node_t::NODE_FALSE:
     201           5 :         lf.set(0.0);
     202           5 :         break;
     203             : 
     204             :     case node_t::NODE_STRING:
     205          40 :         lf.set(lhs->f_str.to_float64());
     206          40 :         break;
     207             : 
     208             :     case node_t::NODE_UNDEFINED:
     209           2 :         lf.set_NaN();
     210           2 :         break;
     211             : 
     212             :     default:
     213             :         // failure (cannot convert)
     214             :         throw exception_internal_error("INTERNAL ERROR: could not convert a literal node to a floating point (lhs)."); // LCOV_EXCL_LINE
     215             : 
     216             :     }
     217             : 
     218         102 :     Float64 rf;
     219         102 :     switch(rhs->f_type)
     220             :     {
     221             :     case node_t::NODE_INT64:
     222           6 :         rf.set(rhs->f_int.get());
     223           6 :         break;
     224             : 
     225             :     case node_t::NODE_FLOAT64:
     226          51 :         rf = rhs->f_float;
     227          51 :         break;
     228             : 
     229             :     case node_t::NODE_TRUE:
     230           1 :         rf.set(1.0);
     231           1 :         break;
     232             : 
     233             :     case node_t::NODE_NULL:
     234             :     case node_t::NODE_FALSE:
     235           4 :         rf.set(0.0);
     236           4 :         break;
     237             : 
     238             :     case node_t::NODE_STRING:
     239          37 :         rf.set(rhs->f_str.to_float64());
     240          37 :         break;
     241             : 
     242             :     case node_t::NODE_UNDEFINED:
     243           3 :         rf.set_NaN();
     244           3 :         break;
     245             : 
     246             :     default:
     247             :         // failure (cannot convert)
     248             :         throw exception_internal_error("INTERNAL ERROR: could not convert a literal node to a floating point (rhs)."); // LCOV_EXCL_LINE
     249             : 
     250             :     }
     251             : 
     252         102 :     if(mode == compare_mode_t::COMPARE_SMART && lf.nearly_equal(rf))
     253             :     {
     254           6 :         return compare_t::COMPARE_EQUAL;
     255             :     }
     256             : 
     257          96 :     return lf.compare(rf);
     258             : }
     259             : 
     260             : 
     261          63 : }
     262             : // namespace as2js
     263             : 
     264             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10