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

          Line data    Source code
       1             : /* node_operator.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 Handle operator types to string and from string.
      43             :  *
      44             :  * The as2js compiler allows you to overload operators in your classes.
      45             :  * This feature requires us to know about the operator name as a string,
      46             :  * not just a type such as NODE_ADD. This file implements two functions
      47             :  * to convert operators types to and from strings.
      48             :  */
      49             : 
      50             : 
      51             : namespace as2js
      52             : {
      53             : 
      54             : 
      55             : 
      56             : /**********************************************************************/
      57             : /**********************************************************************/
      58             : /***  NODE OPERATOR  **************************************************/
      59             : /**********************************************************************/
      60             : /**********************************************************************/
      61             : 
      62             : /** \brief Internal structures and tables used to do operator conversions.
      63             :  *
      64             :  * The following namespace defines a structure and a table of node types
      65             :  * with the name of the operator as a string. For debug purposes, we also
      66             :  * include the line number.
      67             :  */
      68             : namespace
      69             : {
      70             : 
      71             : 
      72             : /** \brief Structure to define an operator.
      73             :  *
      74             :  * This structure defines one operator including a node type, the
      75             :  * name of the operator such as "!" for the logical not, and a
      76             :  * line number. The line number is only used for debug purposes
      77             :  * when a mistake is found in the conversion table.
      78             :  */
      79             : struct operator_to_string_t
      80             : {
      81             :     /** \brief The type of node.
      82             :      *
      83             :      * This parameter defines a node type such as NODE_ADD. Only
      84             :      * operators are to be defined in this table, although there
      85             :      * is nothing that prevents you from adding any type here.
      86             :      */
      87             :     Node::node_t    f_node;
      88             : 
      89             :     /** \brief The name of the operator.
      90             :      *
      91             :      * This entry represents the "name" of the operator. This is
      92             :      * the ASCII representation of the operator such as "!" for
      93             :      * the logical not operator.
      94             :      */
      95             :     char const *    f_name;
      96             : 
      97             :     /** \brief The line on which the operator is defined.
      98             :      *
      99             :      * For debug purposes, when we make changes to the table we
     100             :      * may end up with an invalid table. This line number is used
     101             :      * to generate an error to the programmer who can then fix
     102             :      * the problem quickly instead of trying to guess what is
     103             :      * wrong in the table.
     104             :      */
     105             :     int             f_line;
     106             : };
     107             : 
     108             : /** \brief Table of operators and operator names.
     109             :  *
     110             :  * This table is used to convert operators to strings, and vice versa.
     111             :  * The operators are sorted numerically so we can search them using
     112             :  * a fast binary search algorithm. When compiling in debug mode,
     113             :  * the operator_to_string() function verifies that the order is
     114             :  * proper.
     115             :  *
     116             :  * \sa operator_to_string()
     117             :  */
     118             : operator_to_string_t const g_operator_to_string[] =
     119             : {
     120             :     // single character -- sorted in ASCII
     121             :     { Node::node_t::NODE_LOGICAL_NOT,                     "!", __LINE__ },
     122             :     { Node::node_t::NODE_MODULO,                          "%", __LINE__ },
     123             :     { Node::node_t::NODE_BITWISE_AND,                     "&", __LINE__ },
     124             :     { Node::node_t::NODE_MULTIPLY,                        "*", __LINE__ },
     125             :     { Node::node_t::NODE_ADD,                             "+", __LINE__ },
     126             :     { Node::node_t::NODE_SUBTRACT,                        "-", __LINE__ },
     127             :     { Node::node_t::NODE_DIVIDE,                          "/", __LINE__ },
     128             :     { Node::node_t::NODE_LESS,                            "<", __LINE__ },
     129             :     { Node::node_t::NODE_ASSIGNMENT,                      "=", __LINE__ },
     130             :     { Node::node_t::NODE_GREATER,                         ">", __LINE__ },
     131             :     { Node::node_t::NODE_BITWISE_XOR,                     "^", __LINE__ },
     132             :     { Node::node_t::NODE_BITWISE_OR,                      "|", __LINE__ },
     133             :     { Node::node_t::NODE_BITWISE_NOT,                     "~", __LINE__ },
     134             : 
     135             :     // two or more characters transformed to an enum only
     136             :     { Node::node_t::NODE_ASSIGNMENT_ADD,                  "+=",   __LINE__ },
     137             :     { Node::node_t::NODE_ASSIGNMENT_BITWISE_AND,          "&=",   __LINE__ },
     138             :     { Node::node_t::NODE_ASSIGNMENT_BITWISE_OR,           "|=",   __LINE__ },
     139             :     { Node::node_t::NODE_ASSIGNMENT_BITWISE_XOR,          "^=",   __LINE__ },
     140             :     { Node::node_t::NODE_ASSIGNMENT_DIVIDE,               "/=",   __LINE__ },
     141             :     { Node::node_t::NODE_ASSIGNMENT_LOGICAL_AND,          "&&=",  __LINE__ },
     142             :     { Node::node_t::NODE_ASSIGNMENT_LOGICAL_OR,           "||=",  __LINE__ },
     143             :     { Node::node_t::NODE_ASSIGNMENT_LOGICAL_XOR,          "^^=",  __LINE__ },
     144             :     { Node::node_t::NODE_ASSIGNMENT_MAXIMUM,              ">?=",  __LINE__ },
     145             :     { Node::node_t::NODE_ASSIGNMENT_MINIMUM,              "<?=",  __LINE__ },
     146             :     { Node::node_t::NODE_ASSIGNMENT_MODULO,               "%=",   __LINE__ },
     147             :     { Node::node_t::NODE_ASSIGNMENT_MULTIPLY,             "*=",   __LINE__ },
     148             :     { Node::node_t::NODE_ASSIGNMENT_POWER,                "**=",  __LINE__ },
     149             :     { Node::node_t::NODE_ASSIGNMENT_ROTATE_LEFT,          "<%=",  __LINE__ },
     150             :     { Node::node_t::NODE_ASSIGNMENT_ROTATE_RIGHT,         ">%=",  __LINE__ },
     151             :     { Node::node_t::NODE_ASSIGNMENT_SHIFT_LEFT,           "<<=",  __LINE__ },
     152             :     { Node::node_t::NODE_ASSIGNMENT_SHIFT_RIGHT,          ">>=",  __LINE__ },
     153             :     { Node::node_t::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED, ">>>=", __LINE__ },
     154             :     { Node::node_t::NODE_ASSIGNMENT_SUBTRACT,             "-=",   __LINE__ },
     155             :     { Node::node_t::NODE_CALL,                            "()",   __LINE__ },
     156             :     { Node::node_t::NODE_COMPARE,                         "<=>",  __LINE__ },
     157             :     { Node::node_t::NODE_DECREMENT,                       "--x",  __LINE__ },
     158             :     { Node::node_t::NODE_EQUAL,                           "==",   __LINE__ },
     159             :     { Node::node_t::NODE_GREATER_EQUAL,                   ">=",   __LINE__ },
     160             :     { Node::node_t::NODE_INCREMENT,                       "++x",  __LINE__ },
     161             :     { Node::node_t::NODE_LESS_EQUAL,                      "<=",   __LINE__ },
     162             :     { Node::node_t::NODE_LOGICAL_AND,                     "&&",   __LINE__ },
     163             :     { Node::node_t::NODE_LOGICAL_OR,                      "||",   __LINE__ },
     164             :     { Node::node_t::NODE_LOGICAL_XOR,                     "^^",   __LINE__ },
     165             :     { Node::node_t::NODE_MATCH,                           "~=",   __LINE__ },
     166             :     { Node::node_t::NODE_MAXIMUM,                         ">?",   __LINE__ },
     167             :     { Node::node_t::NODE_MINIMUM,                         "<?",   __LINE__ },
     168             :     { Node::node_t::NODE_NOT_EQUAL,                       "!=",   __LINE__ },
     169             :     { Node::node_t::NODE_NOT_MATCH,                       "!~",   __LINE__ },
     170             :     { Node::node_t::NODE_POST_DECREMENT,                  "x--",  __LINE__ },
     171             :     { Node::node_t::NODE_POST_INCREMENT,                  "x++",  __LINE__ },
     172             :     { Node::node_t::NODE_POWER,                           "**",   __LINE__ },
     173             :     { Node::node_t::NODE_ROTATE_LEFT,                     "<%",   __LINE__ },
     174             :     { Node::node_t::NODE_ROTATE_RIGHT,                    ">%",   __LINE__ },
     175             :     { Node::node_t::NODE_SHIFT_LEFT,                      "<<",   __LINE__ },
     176             :     { Node::node_t::NODE_SHIFT_RIGHT,                     ">>",   __LINE__ },
     177             :     { Node::node_t::NODE_SHIFT_RIGHT_UNSIGNED,            ">>>",  __LINE__ },
     178             :     { Node::node_t::NODE_SMART_MATCH,                     "~~",   __LINE__ },
     179             :     { Node::node_t::NODE_STRICTLY_EQUAL,                  "===",  __LINE__ },
     180             :     { Node::node_t::NODE_STRICTLY_NOT_EQUAL,              "!==",  __LINE__ }
     181             : 
     182             :     // the following does not make it in user redefinable operators
     183             :     //{ Node::node_t::NODE_CONDITIONAL,                   "", __LINE__ },
     184             :     //{ Node::node_t::NODE_DELETE,                        "", __LINE__ },
     185             :     //{ Node::node_t::NODE_IN,                            "", __LINE__ },
     186             :     //{ Node::node_t::NODE_INSTANCEOF,                    "", __LINE__ },
     187             :     //{ Node::node_t::NODE_IS,                            "", __LINE__ },
     188             :     //{ Node::node_t::NODE_LIST,                          "", __LINE__ },
     189             :     //{ Node::node_t::NODE_NEW,                           "", __LINE__ },
     190             :     //{ Node::node_t::NODE_RANGE,                         "", __LINE__ },
     191             :     //{ Node::node_t::NODE_SCOPE,                         "", __LINE__ },
     192             : };
     193             : 
     194             : /** \brief The size of the g_operator_to_string table.
     195             :  *
     196             :  * This variable represents the size, number of structures, in the
     197             :  * g_operator_to_string table.
     198             :  */
     199             : size_t const g_operator_to_string_size = sizeof(g_operator_to_string) / sizeof(g_operator_to_string[0]);
     200             : 
     201             : }
     202             : // no name namespace
     203             : 
     204             : 
     205             : 
     206             : /** \brief Transform an operator to a string.
     207             :  *
     208             :  * This function transforms the specified operator (\p op) to a
     209             :  * printable string. It is generaly used to print out an error
     210             :  * message.
     211             :  *
     212             :  * If the function cannot find the operator, then it returns a
     213             :  * null pointer (be careful, we return a standard C null terminated
     214             :  * string here, not an std::string or as2js::String.)
     215             :  *
     216             :  * \param[in] op  The operator to convert to a string.
     217             :  *
     218             :  * \return A basic null terminated C string with the operator name or nullptr.
     219             :  *
     220             :  * \sa string_to_operator()
     221             :  */
     222      491830 : char const *Node::operator_to_string(node_t op)
     223             : {
     224             : #if defined(_DEBUG) || defined(DEBUG)
     225             :     {
     226             :         // make sure that the node types are properly sorted
     227             :         static bool checked = false;
     228      491830 :         if(!checked)
     229             :         {
     230             :             // check only once
     231           1 :             checked = true;
     232          58 :             for(size_t idx = 1; idx < g_operator_to_string_size; ++idx)
     233             :             {
     234          57 :                 if(g_operator_to_string[idx].f_node <= g_operator_to_string[idx - 1].f_node)
     235             :                 {
     236             :                     std::cerr << "INTERNAL ERROR at offset " << idx                                                     // LCOV_EXCL_LINE
     237             :                               << " (line #" << g_operator_to_string[idx].f_line                                         // LCOV_EXCL_LINE
     238             :                               << ", node type " << static_cast<uint32_t>(g_operator_to_string[idx].f_node)              // LCOV_EXCL_LINE
     239             :                               << " vs. " << static_cast<uint32_t>(g_operator_to_string[idx - 1].f_node)                 // LCOV_EXCL_LINE
     240             :                               << "): the g_operator_to_string table isn't sorted properly. We can't binary search it."  // LCOV_EXCL_LINE
     241             :                               << std::endl;                                                                             // LCOV_EXCL_LINE
     242             :                     throw exception_internal_error("INTERNAL ERROR: node types not properly sorted, cannot properly search for operators using a binary search."); // LCOV_EXCL_LINE
     243             :                 }
     244             :             }
     245             :         }
     246             :     }
     247             : #endif
     248             : 
     249      491830 :     size_t i(0);
     250      491830 :     size_t j(g_operator_to_string_size);
     251     2959371 :     while(i < j)
     252             :     {
     253     2467429 :         size_t p((j - i) / 2 + i);
     254     2467429 :         int r(static_cast<int>(g_operator_to_string[p].f_node) - static_cast<int>(op));
     255     2467429 :         if(r == 0)
     256             :         {
     257      491718 :             return g_operator_to_string[p].f_name;
     258             :         }
     259     1975711 :         if(r < 0)
     260             :         {
     261      885472 :             i = p + 1;
     262             :         }
     263             :         else
     264             :         {
     265     1090239 :             j = p;
     266             :         }
     267             :     }
     268             : 
     269         112 :     return nullptr;
     270             : }
     271             : 
     272             : 
     273             : /** \brief Transform a string in an operator.
     274             :  *
     275             :  * The user may declare operators in his classes. Because of that
     276             :  * the lexer returns identifiers and strings that need to later be
     277             :  * converted to an operator. This function is used for this purpose.
     278             :  *
     279             :  * If the operator is invalid, then the function returns NODE_UNKNOWN.
     280             :  *
     281             :  * \todo
     282             :  * The table is sorted by type_t::NODE_... value. It would be good
     283             :  * to create another table sorted by name. We could declare a static
     284             :  * table which gets initialized on a first call to this function.
     285             :  * Then we could also make use of the binary search here.
     286             :  *
     287             :  * \todo
     288             :  * This is a TBD, I think it is okay, but the compiler may need some
     289             :  * tweaking to work...
     290             :  * It seems that the ++x and x++ (and corresponding --) won't work
     291             :  * right. We should be able to detect that once we try to declare
     292             :  * such operators in a class. The "x" is nice when outputing the
     293             :  * result, but it is problematic when searching for a node type.
     294             :  * However, we certainly have to add it anyway depending on whether
     295             :  * the function has a parameter or not because otherwise we cannot
     296             :  * know whether it is a pre- or a post-increment or -decrement.
     297             :  *
     298             :  * \param[in] str  The string representing the operator to convert.
     299             :  *
     300             :  * \return The node type representing this operator.
     301             :  *
     302             :  * \sa operator_to_string()
     303             :  */
     304       41132 : Node::node_t Node::string_to_operator(String const& str)
     305             : {
     306     1499381 :     for(size_t idx(0); idx < g_operator_to_string_size; ++idx)
     307             :     {
     308             :         // not sorted by name so we use a slow poke search...
     309     1482883 :         if(str == g_operator_to_string[idx].f_name)
     310             :         {
     311       24634 :             return g_operator_to_string[idx].f_node;
     312             :         }
     313             :     }
     314             : 
     315       16498 :     if(str == "<>")
     316             :     {
     317             :         // this is an overload of the '!='
     318           1 :         return node_t::NODE_NOT_EQUAL;
     319             :     }
     320       16497 :     if(str == ":=")
     321             :     {
     322             :         // this is an overload of the '='
     323           1 :         return node_t::NODE_ASSIGNMENT;
     324             :     }
     325             : 
     326       16496 :     return node_t::NODE_UNKNOWN;
     327             : }
     328             : 
     329             : 
     330          63 : }
     331             : // namespace as2js
     332             : 
     333             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10