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

          Line data    Source code
       1             : /* node_convert.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 Convert a Node object to another type.
      43             :  *
      44             :  * The conversion functions allow one to convert a certain number of
      45             :  * Node objects from their current type to a different type.
      46             :  *
      47             :  * Most Node cannot be converted to anything else than the UNKNOWN
      48             :  * Node type, which is used to <em>delete</em> a Node. The various
      49             :  * conversion functions defined below let you know what types are
      50             :  * accepted by each function.
      51             :  *
      52             :  * In most cases the conversion functions will return a Boolean
      53             :  * value. If false, then the conversion did not happen. You are
      54             :  * responsible for checking the result and act on it appropriately.
      55             :  *
      56             :  * Although a conversion function, the set_boolean() function is
      57             :  * actually defined in the node_value.cpp file. It is done that way
      58             :  * because it looks very similar to the set_int64(), set_float64(),
      59             :  * and set_string() functions.
      60             :  */
      61             : 
      62             : 
      63             : namespace as2js
      64             : {
      65             : 
      66             : 
      67             : /**********************************************************************/
      68             : /**********************************************************************/
      69             : /***  DATA CONVERSION  ************************************************/
      70             : /**********************************************************************/
      71             : /**********************************************************************/
      72             : 
      73             : 
      74             : /** \brief Transform any node to NODE_UNKNOWN
      75             :  *
      76             :  * This function marks the node as unknown. Absolutely any node can be
      77             :  * marked as unknown. It is specifically used by the compiler and
      78             :  * optimizer to cancel nodes that cannot otherwise be deleted at
      79             :  * the time they are working on the tree.
      80             :  *
      81             :  * All the children of an unknown node are ignored too (considered
      82             :  * as NODE_UNKNOWN, although they do not all get converted.)
      83             :  *
      84             :  * To remove all the unknown nodes once the compiler is finished,
      85             :  * one can call the clean_tree() function.
      86             :  *
      87             :  * \note
      88             :  * The Node must not be locked.
      89             :  */
      90         344 : void Node::to_unknown()
      91             : {
      92         344 :     modifying();
      93             : 
      94             :     // whatever the type of node we can always convert it to an unknown
      95             :     // node since that's similar to "deleting" the node
      96         173 :     f_type = node_t::NODE_UNKNOWN;
      97             :     // clear the node's data to avoid other problems?
      98         173 : }
      99             : 
     100             : 
     101             : /** \brief Transform a call in a NODE_AS node.
     102             :  *
     103             :  * This function transforms a node defined as NODE_CALL into a NODE_AS.
     104             :  * The special casting syntax looks exactly like a function call. For
     105             :  * this reason the parser returns it as such. The compiler, however,
     106             :  * can determine whether the function name is really a function name
     107             :  * or if it is a type name. If it is a type, then the tree is changed
     108             :  * to represent an AS instruction instead:
     109             :  *
     110             :  * \code
     111             :  *     type ( expression )
     112             :  *     expression AS type
     113             :  * \endcode
     114             :  *
     115             :  * \note
     116             :  * The Node must not be locked.
     117             :  *
     118             :  * \todo
     119             :  * We will need to verify that this is correct and does not introduce
     120             :  * other problems. However, remember that we do not use prototypes in
     121             :  * our world. We have well defined classes so it should work just fine.
     122             :  *
     123             :  * \return true if the conversion happens.
     124             :  */
     125         340 : bool Node::to_as()
     126             : {
     127         340 :     modifying();
     128             : 
     129             :     // "a call to a getter" may be transformed from CALL to AS
     130             :     // because a getter can very much look like a cast (false positive)
     131         170 :     if(node_t::NODE_CALL == f_type)
     132             :     {
     133           1 :         f_type = node_t::NODE_AS;
     134           1 :         return true;
     135             :     }
     136             : 
     137         169 :     return false;
     138             : }
     139             : 
     140             : 
     141             : /** \brief Check whether a node can be converted to Boolean.
     142             :  *
     143             :  * This function is constant and can be used to see whether a node
     144             :  * represents true or false without actually converting the node.
     145             :  *
     146             :  * \li NODE_TRUE -- returned as is
     147             :  * \li NODE_FALSE -- returned as is
     148             :  * \li NODE_NULL -- returns NODE_FALSE
     149             :  * \li NODE_UNDEFINED -- returns NODE_FALSE
     150             :  * \li NODE_INT64 -- returns NODE_TRUE unless the interger is zero
     151             :  *                   in which case NODE_FALSE is returned
     152             :  * \li NODE_FLOAT64 -- returns NODE_TRUE unless the floating point is
     153             :  *                     exactly zero in which case NODE_FALSE is returned
     154             :  * \li NODE_STRING -- returns NODE_TRUE unless the string is empty in
     155             :  *                    which case NODE_FALSE is returned
     156             :  * \li Any other node type -- returns NODE_UNDEFINED
     157             :  *
     158             :  * Note that in this case we completely ignore the content of a string.
     159             :  * The strings "false", "0.0", and "0" all represent Boolean 'true'.
     160             :  *
     161             :  * \return NODE_TRUE, NODE_FALSE, or NODE_UNDEFINED depending on 'this' node
     162             :  *
     163             :  * \sa to_boolean()
     164             :  * \sa set_boolean()
     165             :  */
     166        1587 : Node::node_t Node::to_boolean_type_only() const
     167             : {
     168        1587 :     switch(f_type)
     169             :     {
     170             :     case node_t::NODE_TRUE:
     171             :     case node_t::NODE_FALSE:
     172             :         // already a boolean
     173          29 :         return f_type;
     174             : 
     175             :     case node_t::NODE_NULL:
     176             :     case node_t::NODE_UNDEFINED:
     177          11 :         return node_t::NODE_FALSE;
     178             : 
     179             :     case node_t::NODE_INT64:
     180         111 :         return f_int.get() != 0 ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     181             : 
     182             :     case node_t::NODE_FLOAT64:
     183             : #pragma GCC diagnostic push
     184             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     185        1098 :         return f_float.get() != 0.0 && !f_float.is_NaN() ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     186             : #pragma GCC diagnostic pop
     187             : 
     188             :     case node_t::NODE_STRING:
     189          12 :         return f_str.is_true() ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     190             : 
     191             :     default:
     192             :         // failure (cannot convert)
     193         326 :         return node_t::NODE_UNDEFINED;
     194             : 
     195             :     }
     196             :     /*NOTREACHED*/
     197             : }
     198             : 
     199             : 
     200             : /** \brief Convert this node to a Boolean node.
     201             :  *
     202             :  * This function converts 'this' node to a Boolean node:
     203             :  *
     204             :  * \li NODE_TRUE -- no conversion
     205             :  * \li NODE_FALSE -- no conversion
     206             :  * \li NODE_NULL -- converted to NODE_FALSE
     207             :  * \li NODE_UNDEFINED -- converted to NODE_FALSE
     208             :  * \li NODE_INT64 -- converted to NODE_TRUE unless it is 0
     209             :  *                   in which case it gets converted to NODE_FALSE
     210             :  * \li NODE_FLOAT64 -- converted to NODE_TRUE unless it is 0.0
     211             :  *                     in which case it gets converted to NODE_FALSE
     212             :  * \li NODE_STRING -- converted to NODE_TRUE unless the string is empty
     213             :  *                    in which case it gets converted to NODE_FALSE
     214             :  *
     215             :  * Other input types do not get converted and the function returns false.
     216             :  *
     217             :  * To just test the Boolean value of a node without converting it, call
     218             :  * to_boolean_type_only() instead.
     219             :  *
     220             :  * \note
     221             :  * The Node must not be locked.
     222             :  *
     223             :  * \return true if the conversion succeeds.
     224             :  *
     225             :  * \sa to_boolean_type_only()
     226             :  * \sa set_boolean()
     227             :  */
     228        1582 : bool Node::to_boolean()
     229             : {
     230        1582 :     modifying();
     231             : 
     232        1412 :     switch(f_type)
     233             :     {
     234             :     case node_t::NODE_TRUE:
     235             :     case node_t::NODE_FALSE:
     236             :         // already a boolean
     237          46 :         break;
     238             : 
     239             :     case node_t::NODE_NULL:
     240             :     case node_t::NODE_UNDEFINED:
     241           4 :         f_type = node_t::NODE_FALSE;
     242           4 :         break;
     243             : 
     244             :     case node_t::NODE_INT64:
     245         104 :         f_type = f_int.get() != 0 ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     246         104 :         break;
     247             : 
     248             :     case node_t::NODE_FLOAT64:
     249             : #pragma GCC diagnostic push
     250             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     251        1091 :         f_type = f_float.get() != 0.0 && !f_float.is_NaN() ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     252             : #pragma GCC diagnostic pop
     253        1091 :         break;
     254             : 
     255             :     case node_t::NODE_STRING:
     256           4 :         f_type = f_str.is_true() ? node_t::NODE_TRUE : node_t::NODE_FALSE;
     257           4 :         break;
     258             : 
     259             :     default:
     260             :         // failure (cannot convert)
     261         163 :         return false;
     262             : 
     263             :     }
     264             : 
     265        1249 :     return true;
     266             : }
     267             : 
     268             : 
     269             : /** \brief Convert a getter or setter to a function call.
     270             :  *
     271             :  * This function is used to convert a getter ot a setter to
     272             :  * a function call.
     273             :  *
     274             :  * A read from a member variable is a getter if the name of
     275             :  * the field was actually defined as a 'get' function.
     276             :  *
     277             :  * A write to a member variable is a setter if the name of
     278             :  * the field was actually defined as a 'set' function.
     279             :  *
     280             :  * \code
     281             :  *     class foo_class
     282             :  *     {
     283             :  *         function get field() { ... }
     284             :  *         function set field() { ... }
     285             :  *     };
     286             :  *
     287             :  *     // Convert a getter to a function call
     288             :  *     a = foo.field;
     289             :  *     a = foo.field_getter();
     290             :  *
     291             :  *     // Convert a setter to a function call
     292             :  *     foo.field = a;
     293             :  *     foo.field_setter(a);
     294             :  * \endcode
     295             :  *
     296             :  * The function returns false if 'this' node is not a NODE_MEMBER or
     297             :  * a NODE_ASSIGNMENT.
     298             :  *
     299             :  * \note
     300             :  * This function has no way of knowing what's what.
     301             :  * It just changes the f_type parameter of this node.
     302             :  *
     303             :  * \note
     304             :  * The Node must not be locked.
     305             :  *
     306             :  * \return true if the conversion succeeded.
     307             :  */
     308         340 : bool Node::to_call()
     309             : {
     310         340 :     modifying();
     311             : 
     312             :     // getters are transformed from MEMBER to CALL
     313             :     // setters are transformed from ASSIGNMENT to CALL
     314         340 :     if(node_t::NODE_MEMBER == f_type        // member getter
     315         170 :     || node_t::NODE_ASSIGNMENT == f_type)   // assignment setter
     316             :     {
     317           2 :         f_type = node_t::NODE_CALL;
     318           2 :         return true;
     319             :     }
     320             : 
     321         168 :     return false;
     322             : }
     323             : 
     324             : 
     325             : /** \brief Convert this node to a NODE_IDENTIFIER.
     326             :  *
     327             :  * This function converts the node to an identifier. This is used to
     328             :  * transform some keywords back to an identifier.
     329             :  *
     330             :  * \li NODE_PRIVATE -- "private"
     331             :  * \li NODE_PROTECTED -- "protected"
     332             :  * \li NODE_PUBLIC -- "public"
     333             :  *
     334             :  * At this point this is used to transform these keywords in labels.
     335             :  *
     336             :  * \note
     337             :  * The Node must not be locked.
     338             :  *
     339             :  * \return true if the conversion succeeded.
     340             :  */
     341       24916 : bool Node::to_identifier()
     342             : {
     343       24916 :     modifying();
     344             : 
     345       24746 :     switch(f_type)
     346             :     {
     347             :     case node_t::NODE_IDENTIFIER:
     348             :         // already an identifier
     349           1 :         return true;
     350             : 
     351             :     case node_t::NODE_PRIVATE:
     352        8193 :         f_type = node_t::NODE_IDENTIFIER;
     353        8193 :         set_string("private");
     354        8193 :         return true;
     355             : 
     356             :     case node_t::NODE_PROTECTED:
     357        8193 :         f_type = node_t::NODE_IDENTIFIER;
     358        8193 :         set_string("protected");
     359        8193 :         return true;
     360             : 
     361             :     case node_t::NODE_PUBLIC:
     362        8193 :         f_type = node_t::NODE_IDENTIFIER;
     363        8193 :         set_string("public");
     364        8193 :         return true;
     365             : 
     366             :     default:
     367             :         // failure (cannot convert)
     368         166 :         return false;
     369             : 
     370             :     }
     371             :     /*NOTREACHED*/
     372             : }
     373             : 
     374             : 
     375             : /** \brief Convert this node to a NODE_INT64.
     376             :  *
     377             :  * This function converts the node to an integer number,
     378             :  * just like JavaScript would do (outside of the fact that
     379             :  * JavaScript only supports floating points...) This means
     380             :  * converting the following type of nodes as specified:
     381             :  *
     382             :  * \li NODE_INT64 -- no conversion
     383             :  * \li NODE_FLOAT64 -- convert to integer
     384             :  * \li NODE_TRUE -- convert to 1
     385             :  * \li NODE_FALSE -- convert to 0
     386             :  * \li NODE_NULL -- convert to 0
     387             :  * \li NODE_STRING -- convert to integer if valid, zero otherwise (NaN is
     388             :  *                    not possible in an integer)
     389             :  * \li NODE_UNDEFINED -- convert to 0 (NaN is not possible in an integer)
     390             :  *
     391             :  * This function converts strings. If the string represents a
     392             :  * valid integer, convert to that integer. In this case the full 64 bits
     393             :  * are supported. If the string represents a floating point number, then
     394             :  * the number is first converted to a floating point, then cast to an
     395             :  * integer using the floor() function. If the floating point is too large
     396             :  * for the integer, then the maximum or minimum number are used as the
     397             :  * result. String that do not represent a number (integer or floating
     398             :  * point) are transformed to zero (0). This is a similar behavior to
     399             :  * the 'undefined' conversion.
     400             :  *
     401             :  * \note
     402             :  * The Node must not be locked.
     403             :  *
     404             :  * \return true if the conversion succeeded.
     405             :  */
     406        1609 : bool Node::to_int64()
     407             : {
     408        1609 :     modifying();
     409             : 
     410        1439 :     switch(f_type)
     411             :     {
     412             :     case node_t::NODE_INT64:
     413         155 :         return true;
     414             : 
     415             :     case node_t::NODE_FLOAT64:
     416        1110 :         if(f_float.is_NaN() || f_float.is_infinity())
     417             :         {
     418             :             // the C-like cast would use 0x800...000
     419             :             // JavaScript expects zero instead
     420          19 :             f_int.set(0);
     421             :         }
     422             :         else
     423             :         {
     424        1091 :             f_int.set(f_float.get()); // C-like cast to integer with a floor() (no rounding)
     425             :         }
     426        1110 :         break;
     427             : 
     428             :     case node_t::NODE_TRUE:
     429           1 :         f_int.set(1);
     430           1 :         break;
     431             : 
     432             :     case node_t::NODE_NULL:
     433             :     case node_t::NODE_FALSE:
     434             :     case node_t::NODE_UNDEFINED: // should return NaN, not possible with an integer...
     435           3 :         f_int.set(0);
     436           3 :         break;
     437             : 
     438             :     case node_t::NODE_STRING:
     439           7 :         if(f_str.is_int64())
     440             :         {
     441           4 :             f_int.set(f_str.to_int64());
     442             :         }
     443           3 :         else if(f_str.is_float64())
     444             :         {
     445           2 :             f_int.set(f_str.to_float64()); // C-like cast to integer with a floor() (no rounding)
     446             :         }
     447             :         else
     448             :         {
     449           1 :             f_int.set(0); // should return NaN, not possible with an integer...
     450             :         }
     451           7 :         break;
     452             : 
     453             :     default:
     454             :         // failure (cannot convert)
     455         163 :         return false;
     456             : 
     457             :     }
     458             : 
     459        1121 :     f_type = node_t::NODE_INT64;
     460        1121 :     return true;
     461             : }
     462             : 
     463             : 
     464             : /** \brief Convert this node to a NODE_FLOAT64.
     465             :  *
     466             :  * This function converts the node to a floating point number,
     467             :  * just like JavaScript would do. This means converting the following
     468             :  * type of nodes:
     469             :  *
     470             :  * \li NODE_INT64 -- convert to a float
     471             :  * \li NODE_FLOAT64 -- no conversion
     472             :  * \li NODE_TRUE -- convert to 1.0
     473             :  * \li NODE_FALSE -- convert to 0.0
     474             :  * \li NODE_NULL -- convert to 0.0
     475             :  * \li NODE_STRING -- convert to float if valid, otherwise NaN
     476             :  * \li NODE_UNDEFINED -- convert to NaN
     477             :  *
     478             :  * This function converts strings. If the string represents an integer,
     479             :  * it will be converted to the nearest floating point number. If the
     480             :  * string does not represent a number (including an empty string),
     481             :  * then the float is set to NaN.
     482             :  *
     483             :  * \note
     484             :  * The Node must not be locked.
     485             :  *
     486             :  * \return true if the conversion succeeded.
     487             :  */
     488        1643 : bool Node::to_float64()
     489             : {
     490        1643 :     modifying();
     491             : 
     492        1473 :     switch(f_type)
     493             :     {
     494             :     case node_t::NODE_INT64:
     495         119 :         f_float.set(f_int.get());
     496         119 :         break;
     497             : 
     498             :     case node_t::NODE_FLOAT64:
     499        1178 :         return true;
     500             : 
     501             :     case node_t::NODE_TRUE:
     502           2 :         f_float.set(1.0);
     503           2 :         break;
     504             : 
     505             :     case node_t::NODE_NULL:
     506             :     case node_t::NODE_FALSE:
     507           4 :         f_float.set(0.0);
     508           4 :         break;
     509             : 
     510             :     case node_t::NODE_STRING:
     511           5 :         f_float.set(f_str.to_float64());
     512           5 :         break;
     513             : 
     514             :     case node_t::NODE_UNDEFINED:
     515           2 :         f_float.set_NaN();
     516           2 :         break;
     517             : 
     518             :     default:
     519             :         // failure (cannot convert)
     520         163 :         return false;
     521             : 
     522             :     }
     523             : 
     524         132 :     f_type = node_t::NODE_FLOAT64;
     525         132 :     return true;
     526             : }
     527             : 
     528             : 
     529             : /** \brief Convert this node to a label.
     530             :  *
     531             :  * This function converts a NODE_IDENTIFIER node to a NODE_LABEL node.
     532             :  *
     533             :  * \note
     534             :  * The Node must not be locked.
     535             :  *
     536             :  * \return true if the conversion succeeded.
     537             :  */
     538       41300 : bool Node::to_label()
     539             : {
     540       41300 :     modifying();
     541             : 
     542       41130 :     switch(f_type)
     543             :     {
     544             :     case node_t::NODE_IDENTIFIER:
     545       40961 :         f_type = node_t::NODE_LABEL;
     546       40961 :         break;
     547             : 
     548             :     default:
     549             :         // failure (cannot convert)
     550         169 :         return false;
     551             : 
     552             :     }
     553             : 
     554       40961 :     return true;
     555             : }
     556             : 
     557             : 
     558             : /** \brief Convert this node to a number.
     559             :  *
     560             :  * This function converts the node to a number pretty much
     561             :  * like JavaScript would do, except that literals that represent
     562             :  * an exact integers are converted to an integer instead of a
     563             :  * floating point.
     564             :  *
     565             :  * If the node already is an integer or a floating point, then
     566             :  * no conversion takes place, but it is considered valid and
     567             :  * thus the function returns true.
     568             :  *
     569             :  * This means converting the following type of nodes:
     570             :  *
     571             :  * \li NODE_INT64 -- no conversion
     572             :  * \li NODE_FLOAT64 -- no conversion
     573             :  * \li NODE_TRUE -- convert to 1 (INT64)
     574             :  * \li NODE_FALSE -- convert to 0 (INT64)
     575             :  * \li NODE_NULL -- convert to 0 (INT64)
     576             :  * \li NODE_UNDEFINED -- convert to NaN (FLOAT64)
     577             :  * \li NODE_STRING -- converted to a float, NaN if not a valid float,
     578             :  *                    however, zero if empty.
     579             :  *
     580             :  * This function converts strings to a floating point, even if the
     581             :  * value represents an integer. It is done that way because JavaScript
     582             :  * expects a 'number' and that is expected to be a floating point.
     583             :  *
     584             :  * \note
     585             :  * The Node must not be locked.
     586             :  *
     587             :  * \return true if the conversion succeeded.
     588             :  */
     589        1581 : bool Node::to_number()
     590             : {
     591        1581 :     modifying();
     592             : 
     593        1411 :     switch(f_type)
     594             :     {
     595             :     case node_t::NODE_INT64:
     596             :     case node_t::NODE_FLOAT64:
     597        1235 :         break;
     598             : 
     599             :     case node_t::NODE_TRUE:
     600           2 :         f_type = node_t::NODE_INT64;
     601           2 :         f_int.set(1);
     602           2 :         break;
     603             : 
     604             :     case node_t::NODE_NULL:
     605             :     case node_t::NODE_FALSE:
     606           4 :         f_type = node_t::NODE_INT64;
     607           4 :         f_int.set(0);
     608           4 :         break;
     609             : 
     610             :     case node_t::NODE_UNDEFINED:
     611           2 :         f_type = node_t::NODE_FLOAT64;
     612           2 :         f_float.set_NaN();
     613           2 :         break;
     614             : 
     615             :     case node_t::NODE_STRING:
     616             :         // JavaScript tends to force conversions from stings to numbers
     617             :         // when possible (actually it nearly always is, and strings
     618             :         // often become NaN as a result... the '+' and '+=' operators
     619             :         // are an exception; also relational operators do not convert
     620             :         // strings if both the left hand side and the right hand side
     621             :         // are strings.)
     622           5 :         f_type = node_t::NODE_FLOAT64;
     623           5 :         f_float.set(f_str.to_float64());
     624           5 :         break;
     625             : 
     626             :     default:
     627             :         // failure (cannot convert)
     628         163 :         return false;
     629             : 
     630             :     }
     631             : 
     632        1248 :     return true;
     633             : }
     634             : 
     635             : 
     636             : /** \brief Transform a node to a string.
     637             :  *
     638             :  * This function transforms a node from what it is to a string. If the
     639             :  * transformation is successful, the function returns true. Note that
     640             :  * the function does not throw if the type of 'this' cannot be
     641             :  * converted to a string.
     642             :  *
     643             :  * The nodes that can be converted to a string are:
     644             :  *
     645             :  * \li NODE_STRING -- unchanged
     646             :  * \li NODE_IDENTIFIER -- the identifier is now a string
     647             :  * \li NODE_UNDEFINED -- changed to "undefined"
     648             :  * \li NODE_NULL -- changed to "null"
     649             :  * \li NODE_TRUE -- changed to "true"
     650             :  * \li NODE_FALSE -- changed to "false"
     651             :  * \li NODE_INT64 -- changed to a string representation
     652             :  * \li NODE_FLOAT64 -- changed to a string representation
     653             :  *
     654             :  * The conversion of a floating point is not one to one compatible with
     655             :  * what a JavaScript implementation would otherwise do. This is due to
     656             :  * the fact that Java tends to convert floating points in a slightly
     657             :  * different way than C/C++. None the less, the results are generally
     658             :  * very close (to the 4th decimal digit.)
     659             :  *
     660             :  * The NaN floating point is converted to the string "NaN".
     661             :  *
     662             :  * The floating point +0.0 and -0.0 numbers are converted to exactly "0".
     663             :  *
     664             :  * The floating point +Infinity is converted to the string "Infinity".
     665             :  *
     666             :  * The floating point -Infinity is converted to the string "-Infinity".
     667             :  *
     668             :  * Other numbers are converted as floating points with a decimal point,
     669             :  * although floating points that represent an integer may be output as
     670             :  * an integer.
     671             :  *
     672             :  * \note
     673             :  * The Node must not be locked.
     674             :  *
     675             :  * \return true if the conversion succeeded, false otherwise.
     676             :  */
     677        1557 : bool Node::to_string()
     678             : {
     679        1557 :     modifying();
     680             : 
     681        1387 :     switch(f_type)
     682             :     {
     683             :     case node_t::NODE_STRING:
     684          15 :         return true;
     685             : 
     686             :     case node_t::NODE_IDENTIFIER:
     687             :         // this happens with special identifiers that are strings in the end
     688           1 :         break;
     689             : 
     690             :     case node_t::NODE_UNDEFINED:
     691           3 :         f_str = "undefined";
     692           3 :         break;
     693             : 
     694             :     case node_t::NODE_NULL:
     695           3 :         f_str = "null";
     696           3 :         break;
     697             : 
     698             :     case node_t::NODE_TRUE:
     699           3 :         f_str = "true";
     700           3 :         break;
     701             : 
     702             :     case node_t::NODE_FALSE:
     703           3 :         f_str = "false";
     704           3 :         break;
     705             : 
     706             :     case node_t::NODE_INT64:
     707         103 :         f_str = std::to_string(f_int.get());
     708         103 :         break;
     709             : 
     710             :     case node_t::NODE_FLOAT64:
     711             : #pragma GCC diagnostic push
     712             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     713             :     {
     714        1094 :         Float64::float64_type const value(f_float.get());
     715        1094 :         if(f_float.is_NaN())
     716             :         {
     717           1 :             f_str = "NaN";
     718             :         }
     719        1093 :         else if(value == 0.0)
     720             :         {
     721             :             // make sure it does not become "0.0"
     722           1 :             f_str = "0";
     723             :         }
     724        1092 :         else if(f_float.is_negative_infinity())
     725             :         {
     726           1 :             f_str = "-Infinity";
     727             :         }
     728        1091 :         else if(f_float.is_positive_infinity())
     729             :         {
     730           1 :             f_str = "Infinity";
     731             :         }
     732             :         else
     733             :         {
     734        1090 :             f_str = std::to_string(value);
     735        1090 :             if(f_str.find('.') != f_str.npos)
     736             :             {
     737        2301 :                 while(f_str.back() == '0')
     738             :                 {
     739         121 :                     f_str.pop_back();
     740             :                 }
     741        1090 :                 if(f_str.back() == '.')
     742             :                 {
     743           1 :                     f_str.pop_back();
     744             :                 }
     745             :             }
     746             :         }
     747             :     }
     748             : #pragma GCC diagnostic pop
     749        1094 :         break;
     750             : 
     751             :     default:
     752             :         // failure (cannot convert)
     753         162 :         return false;
     754             : 
     755             :     }
     756        1210 :     f_type = node_t::NODE_STRING;
     757             : 
     758        1210 :     return true;
     759             : }
     760             : 
     761             : 
     762             : /** \brief Transform an identifier into a NODE_VIDENTIFIER.
     763             :  *
     764             :  * This function is used to transform an identifier in a variable
     765             :  * identifier. By default identifiers may represent object names.
     766             :  * However, when written between parenthesis, they always represent
     767             :  * a variable. This can be important as certain syntax are not
     768             :  * at all equivalent:
     769             :  *
     770             :  * \code
     771             :  *    (a).field      // a becomes a NODE_VIDENTIFIER
     772             :  *    a.field
     773             :  * \endcode
     774             :  *
     775             :  * In the first case, (a) is transform with the content of variable
     776             :  * 'a' and that resulting object is used to access 'field'.
     777             :  *
     778             :  * In the second case, 'a' itself represents an object and we are accessing
     779             :  * that object's 'field' directly.
     780             :  *
     781             :  * \note
     782             :  * Why do we need this distinction? Parenthesis used for grouping are
     783             :  * not saved in the resulting tree of nodes. For that reason, at the time
     784             :  * we parse that result, we could not distinguish between both
     785             :  * expressions. With the NODE_VIDENTIFIER, we can correct that problem.
     786             :  *
     787             :  * \note
     788             :  * The Node must not be locked.
     789             :  *
     790             :  * \exception exception_internal_error
     791             :  * This exception is raised if the input node is not a NODE_IDENTIFIER.
     792             :  */
     793       24916 : void Node::to_videntifier()
     794             : {
     795       24916 :     modifying();
     796             : 
     797       24746 :     if(node_t::NODE_IDENTIFIER != f_type)
     798             :     {
     799         169 :         throw exception_internal_error("to_videntifier() called with a node other than a NODE_IDENTIFIER node");
     800             :     }
     801             : 
     802       24577 :     f_type = node_t::NODE_VIDENTIFIER;
     803       24577 : }
     804             : 
     805             : 
     806             : /** \brief Transform a variable into a variable of attributes.
     807             :  *
     808             :  * When compiling the tree, the code in compiler_variable.cpp may detect
     809             :  * that a variable is specifically used to represent a list of attributes.
     810             :  * When that happens, the compiler transforms the variable calling
     811             :  * this function.
     812             :  *
     813             :  * The distinction makes it a lot easier to deal with the variable later.
     814             :  *
     815             :  * \note
     816             :  * The Node must not be locked.
     817             :  *
     818             :  * \exception exception_internal_error
     819             :  * This exception is raised if 'this' node is not a NODE_VARIABLE.
     820             :  */
     821         340 : void Node::to_var_attributes()
     822             : {
     823         340 :     modifying();
     824             : 
     825         170 :     if(node_t::NODE_VARIABLE != f_type)
     826             :     {
     827         169 :         throw exception_internal_error("to_var_attribute() called with a node other than a NODE_VARIABLE node");
     828             :     }
     829             : 
     830           1 :     f_type = node_t::NODE_VAR_ATTRIBUTES;
     831           1 : }
     832             : 
     833             : 
     834          63 : }
     835             : // namespace as2js
     836             : 
     837             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10