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

          Line data    Source code
       1             : /* node.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             : #include    "as2js/message.h"
      40             : 
      41             : #include    <controlled_vars/controlled_vars_auto_enum_init.h>
      42             : 
      43             : #include    <algorithm>
      44             : #include    <sstream>
      45             : #include    <iomanip>
      46             : 
      47             : 
      48             : /** \file
      49             :  * \brief Implement the basic node functions.
      50             :  *
      51             :  * This file includes the node allocation, switch operator, position,
      52             :  * links, variables, and label.
      53             :  *
      54             :  * Other parts are in other files. It was broken up as the Node object
      55             :  * implementation is quite large.
      56             :  */
      57             : 
      58             : 
      59             : namespace as2js
      60             : {
      61             : 
      62             : 
      63             : 
      64             : /**********************************************************************/
      65             : /**********************************************************************/
      66             : /***  NODE  ***********************************************************/
      67             : /**********************************************************************/
      68             : /**********************************************************************/
      69             : 
      70             : 
      71             : 
      72             : /** \brief Initialize a node.
      73             :  *
      74             :  * This function initializes a new node. The specified type is assigned to
      75             :  * the new node as expected.
      76             :  *
      77             :  * If the \p type parameter does not represent a valid type of node, then
      78             :  * the function throws. This means only valid type of nodes can be created.
      79             :  *
      80             :  * Once created, a node representing a literal can have its value defined
      81             :  * using one of the set_...() functions. Note that the set_boolean()
      82             :  * function is a special case which converts the node to either NODE_TRUE
      83             :  * or NODE_FALSE.
      84             :  *
      85             :  * It is also expected that you will set the position of the token using
      86             :  * the set_position() function.
      87             :  *
      88             :  * \note
      89             :  * At this time we accept all the different types at creation time. We
      90             :  * may restrict this later to only nodes that are expected to be created
      91             :  * in this way. For example, a NODE_VIDENTIFIER cannot be created directly,
      92             :  * instead it is expected that you would create a NODE_IDENTIFIER and then
      93             :  * call the to_videntifier() function to conver the node.
      94             :  *
      95             :  * \exception exception_incompatible_node_type
      96             :  * This exception is raised of the specified type does not correspond to
      97             :  * one of the allowed node_t::NODE_... definitions.
      98             :  *
      99             :  * \param[in] type  The type of node to create.
     100             :  *
     101             :  * \sa to_videntifier()
     102             :  * \sa set_boolean()
     103             :  * \sa set_int64()
     104             :  * \sa set_float64()
     105             :  * \sa set_string()
     106             :  * \sa set_position()
     107             :  */
     108    67176012 : Node::Node(node_t type)
     109    67177088 :     : f_type(type)
     110             :     //, f_flags() -- auto-init
     111             :     //, f_attributes() -- auto-init
     112             :     //, f_switch_operator(NODE_UNKNOWN) -- auto-init
     113             :     //, f_lock(0) -- auto-init
     114             :     //, f_position() -- auto-init
     115             :     //, f_int() -- auto-init
     116             :     //, f_float() -- auto-init
     117             :     //, f_str() -- auto-init
     118             :     //, f_parent() -- auto-init
     119             :     //, f_offset(0) -- auto-init
     120             :     //, f_children() -- auto-init
     121             :     //, f_link() -- auto-init
     122             :     //, f_variables() -- auto-init
     123             :     //, f_labels() -- auto-init
     124             : {
     125    67176012 :     switch(type)
     126             :     {
     127             :     case node_t::NODE_EOF:
     128             :     case node_t::NODE_UNKNOWN:
     129             :     case node_t::NODE_ADD:
     130             :     case node_t::NODE_BITWISE_AND:
     131             :     case node_t::NODE_BITWISE_NOT:
     132             :     case node_t::NODE_ASSIGNMENT:
     133             :     case node_t::NODE_BITWISE_OR:
     134             :     case node_t::NODE_BITWISE_XOR:
     135             :     case node_t::NODE_CLOSE_CURVLY_BRACKET:
     136             :     case node_t::NODE_CLOSE_PARENTHESIS:
     137             :     case node_t::NODE_CLOSE_SQUARE_BRACKET:
     138             :     case node_t::NODE_COLON:
     139             :     case node_t::NODE_COMMA:
     140             :     case node_t::NODE_CONDITIONAL:
     141             :     case node_t::NODE_DIVIDE:
     142             :     case node_t::NODE_GREATER:
     143             :     case node_t::NODE_LESS:
     144             :     case node_t::NODE_LOGICAL_NOT:
     145             :     case node_t::NODE_MODULO:
     146             :     case node_t::NODE_MULTIPLY:
     147             :     case node_t::NODE_OPEN_CURVLY_BRACKET:
     148             :     case node_t::NODE_OPEN_PARENTHESIS:
     149             :     case node_t::NODE_OPEN_SQUARE_BRACKET:
     150             :     case node_t::NODE_MEMBER:
     151             :     case node_t::NODE_SEMICOLON:
     152             :     case node_t::NODE_SUBTRACT:
     153             :     case node_t::NODE_ABSTRACT:
     154             :     case node_t::NODE_ARRAY:
     155             :     case node_t::NODE_ARRAY_LITERAL:
     156             :     case node_t::NODE_AS:
     157             :     case node_t::NODE_ASSIGNMENT_ADD:
     158             :     case node_t::NODE_ASSIGNMENT_BITWISE_AND:
     159             :     case node_t::NODE_ASSIGNMENT_BITWISE_OR:
     160             :     case node_t::NODE_ASSIGNMENT_BITWISE_XOR:
     161             :     case node_t::NODE_ASSIGNMENT_DIVIDE:
     162             :     case node_t::NODE_ASSIGNMENT_LOGICAL_AND:
     163             :     case node_t::NODE_ASSIGNMENT_LOGICAL_OR:
     164             :     case node_t::NODE_ASSIGNMENT_LOGICAL_XOR:
     165             :     case node_t::NODE_ASSIGNMENT_MAXIMUM:
     166             :     case node_t::NODE_ASSIGNMENT_MINIMUM:
     167             :     case node_t::NODE_ASSIGNMENT_MODULO:
     168             :     case node_t::NODE_ASSIGNMENT_MULTIPLY:
     169             :     case node_t::NODE_ASSIGNMENT_POWER:
     170             :     case node_t::NODE_ASSIGNMENT_ROTATE_LEFT:
     171             :     case node_t::NODE_ASSIGNMENT_ROTATE_RIGHT:
     172             :     case node_t::NODE_ASSIGNMENT_SHIFT_LEFT:
     173             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT:
     174             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
     175             :     case node_t::NODE_ASSIGNMENT_SUBTRACT:
     176             :     case node_t::NODE_ATTRIBUTES:
     177             :     case node_t::NODE_AUTO:
     178             :     case node_t::NODE_BOOLEAN:
     179             :     case node_t::NODE_BREAK:
     180             :     case node_t::NODE_BYTE:
     181             :     case node_t::NODE_CALL:
     182             :     case node_t::NODE_CASE:
     183             :     case node_t::NODE_CATCH:
     184             :     case node_t::NODE_CHAR:
     185             :     case node_t::NODE_CLASS:
     186             :     case node_t::NODE_COMPARE:
     187             :     case node_t::NODE_CONST:
     188             :     case node_t::NODE_CONTINUE:
     189             :     case node_t::NODE_DEBUGGER:
     190             :     case node_t::NODE_DECREMENT:
     191             :     case node_t::NODE_DEFAULT:
     192             :     case node_t::NODE_DELETE:
     193             :     case node_t::NODE_DIRECTIVE_LIST:
     194             :     case node_t::NODE_DO:
     195             :     case node_t::NODE_DOUBLE:
     196             :     case node_t::NODE_ELSE:
     197             :     case node_t::NODE_EMPTY:
     198             :     case node_t::NODE_ENUM:
     199             :     case node_t::NODE_ENSURE:
     200             :     case node_t::NODE_EQUAL:
     201             :     case node_t::NODE_EXCLUDE:
     202             :     case node_t::NODE_EXTENDS:
     203             :     case node_t::NODE_EXPORT:
     204             :     case node_t::NODE_FALSE:
     205             :     case node_t::NODE_FINAL:
     206             :     case node_t::NODE_FINALLY:
     207             :     case node_t::NODE_FLOAT:
     208             :     case node_t::NODE_FLOAT64:
     209             :     case node_t::NODE_FOR:
     210             :     case node_t::NODE_FUNCTION:
     211             :     case node_t::NODE_GOTO:
     212             :     case node_t::NODE_GREATER_EQUAL:
     213             :     case node_t::NODE_IDENTIFIER:
     214             :     case node_t::NODE_IF:
     215             :     case node_t::NODE_IMPLEMENTS:
     216             :     case node_t::NODE_IMPORT:
     217             :     case node_t::NODE_IN:
     218             :     case node_t::NODE_INCLUDE:
     219             :     case node_t::NODE_INCREMENT:
     220             :     case node_t::NODE_INLINE:
     221             :     case node_t::NODE_INSTANCEOF:
     222             :     case node_t::NODE_INT64:
     223             :     case node_t::NODE_INTERFACE:
     224             :     case node_t::NODE_INVARIANT:
     225             :     case node_t::NODE_IS:
     226             :     case node_t::NODE_LABEL:
     227             :     case node_t::NODE_LESS_EQUAL:
     228             :     case node_t::NODE_LIST:
     229             :     case node_t::NODE_LOGICAL_AND:
     230             :     case node_t::NODE_LOGICAL_OR:
     231             :     case node_t::NODE_LOGICAL_XOR:
     232             :     case node_t::NODE_LONG:
     233             :     case node_t::NODE_MATCH:
     234             :     case node_t::NODE_MAXIMUM:
     235             :     case node_t::NODE_MINIMUM:
     236             :     case node_t::NODE_NAME:
     237             :     case node_t::NODE_NAMESPACE:
     238             :     case node_t::NODE_NATIVE:
     239             :     case node_t::NODE_NEW:
     240             :     case node_t::NODE_NOT_EQUAL:
     241             :     case node_t::NODE_NOT_MATCH:
     242             :     case node_t::NODE_NULL:
     243             :     case node_t::NODE_OBJECT_LITERAL:
     244             :     case node_t::NODE_PACKAGE:
     245             :     case node_t::NODE_PARAM:
     246             :     case node_t::NODE_PARAMETERS:
     247             :     case node_t::NODE_PARAM_MATCH:
     248             :     case node_t::NODE_POST_DECREMENT:
     249             :     case node_t::NODE_POST_INCREMENT:
     250             :     case node_t::NODE_POWER:
     251             :     case node_t::NODE_PRIVATE:
     252             :     case node_t::NODE_PROGRAM:
     253             :     case node_t::NODE_PROTECTED:
     254             :     case node_t::NODE_PUBLIC:
     255             :     case node_t::NODE_RANGE:
     256             :     case node_t::NODE_REGULAR_EXPRESSION:
     257             :     case node_t::NODE_REQUIRE:
     258             :     case node_t::NODE_REST:
     259             :     case node_t::NODE_RETURN:
     260             :     case node_t::NODE_ROOT:
     261             :     case node_t::NODE_ROTATE_LEFT:
     262             :     case node_t::NODE_ROTATE_RIGHT:
     263             :     case node_t::NODE_SCOPE:
     264             :     case node_t::NODE_SET:
     265             :     case node_t::NODE_SHIFT_LEFT:
     266             :     case node_t::NODE_SHIFT_RIGHT:
     267             :     case node_t::NODE_SHIFT_RIGHT_UNSIGNED:
     268             :     case node_t::NODE_SMART_MATCH:
     269             :     case node_t::NODE_SHORT:
     270             :     case node_t::NODE_STATIC:
     271             :     case node_t::NODE_STRICTLY_EQUAL:
     272             :     case node_t::NODE_STRICTLY_NOT_EQUAL:
     273             :     case node_t::NODE_STRING:
     274             :     case node_t::NODE_SUPER:
     275             :     case node_t::NODE_SWITCH:
     276             :     case node_t::NODE_SYNCHRONIZED:
     277             :     case node_t::NODE_THEN:
     278             :     case node_t::NODE_THIS:
     279             :     case node_t::NODE_THROW:
     280             :     case node_t::NODE_THROWS:
     281             :     case node_t::NODE_TRANSIENT:
     282             :     case node_t::NODE_TRUE:
     283             :     case node_t::NODE_TRY:
     284             :     case node_t::NODE_TYPE:
     285             :     case node_t::NODE_TYPEOF:
     286             :     case node_t::NODE_UNDEFINED:
     287             :     case node_t::NODE_USE:
     288             :     case node_t::NODE_VAR:
     289             :     case node_t::NODE_VARIABLE:
     290             :     case node_t::NODE_VAR_ATTRIBUTES:
     291             :     case node_t::NODE_VIDENTIFIER:
     292             :     case node_t::NODE_VOID:
     293             :     case node_t::NODE_VOLATILE:
     294             :     case node_t::NODE_WHILE:
     295             :     case node_t::NODE_WITH:
     296             :     case node_t::NODE_YIELD:
     297    67174936 :         break;
     298             : 
     299             :     // WARNING: we use default here because some people may call the
     300             :     //          function with something other than a properly defined
     301             :     //          node_t type
     302             :     default:
     303             :         // ERROR: some values are not valid as a type
     304        1076 :         throw exception_incompatible_node_type("invalid type used to create a node");
     305             : 
     306             :     }
     307    67174936 : }
     308             : 
     309             : 
     310             : /** \brief Verify that a node is clean when deleting it.
     311             :  *
     312             :  * This function ensures that a node is clean, as in, not locked,
     313             :  * when it gets deleted.
     314             :  *
     315             :  * If we properly make use of the NodeLock, then a node cannot get
     316             :  * deleted until all the locks get canceled with an unlock() call.
     317             :  *
     318             :  * \exception exception_exit
     319             :  * A destructor should not throw, yet we want to have a drastic
     320             :  * error because deleting a locked node is a bug. So the exit
     321             :  * exception is raised here. This way, also, we can capture the
     322             :  * exception in our unit tests. The side effect is that other
     323             :  * parts of the Node object do not get properly cleaned up. It
     324             :  * is fine in the unit test, and it is a totally fatal error
     325             :  * otherwise, so I am not concerned with that problem.
     326             :  * std::abort(), on the other hand, could not be properly tested
     327             :  * from our unit tests (at least, not easily).
     328             :  */
     329   134349872 : Node::~Node() noexcept(false)
     330             : {
     331    67174936 :     if(f_lock > 0)
     332             :     {
     333             :         // Argh! A throw in a destructor... Yet this is a fatal
     334             :         // error and it should never ever happen except in our
     335             :         // unit tests to verify that it does catch such a bug
     336           1 :         Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_NOT_ALLOWED);
     337           1 :         msg << "a node got deleted while still locked.";
     338             : 
     339             :         // for security reasons, we do not try to throw another
     340             :         // exception if the system is already trying to process
     341             :         // an existing exception
     342           1 :         if(std::uncaught_exception())
     343             :         {
     344             :             // still we cannot continue...
     345             :             std::abort(); // LCOV_EXCL_LINE
     346             :         }
     347             : 
     348           1 :         throw exception_exit(1, "a node got deleted while still locked.");
     349             :     }
     350    67174935 : }
     351             : 
     352             : 
     353             : 
     354             : /**********************************************************************/
     355             : /**********************************************************************/
     356             : /***  NODE SWITCH  ****************************************************/
     357             : /**********************************************************************/
     358             : /**********************************************************************/
     359             : 
     360             : 
     361             : /** \brief Retrieve the switch operator.
     362             :  *
     363             :  * A switch statement can be constrained to use a specific operator
     364             :  * using the with() syntax as in:
     365             :  *
     366             :  * \code
     367             :  * switch(foo) with(===)
     368             :  * {
     369             :  *    ...
     370             :  * }
     371             :  * \endcode
     372             :  *
     373             :  * This operator is saved in the switch node and can later be retrieved
     374             :  * with this function.
     375             :  *
     376             :  * \exception exception_internal_error
     377             :  * If the function is called on a node of a type other than NODE_SWITCH
     378             :  * then this exception is raised.
     379             :  *
     380             :  * \return The operator of the switch statement, or NODE_UNKNOWN if undefined.
     381             :  *
     382             :  * \sa set_switch_operator()
     383             :  */
     384        4280 : Node::node_t Node::get_switch_operator() const
     385             : {
     386        4280 :     if(node_t::NODE_SWITCH != f_type)
     387             :     {
     388         169 :         throw exception_internal_error("INTERNAL ERROR: get_switch_operator() called on a node which is not a switch node.");
     389             :     }
     390             : 
     391        4111 :     return f_switch_operator;
     392             : }
     393             : 
     394             : 
     395             : /** \brief Set the switch statement operator.
     396             :  *
     397             :  * This function saves the operator defined following the switch statement
     398             :  * using the with() instruction as in:
     399             :  *
     400             :  * \code
     401             :  * switch(foo) with(===)
     402             :  * {
     403             :  *    ...
     404             :  * }
     405             :  * \endcode
     406             :  *
     407             :  * The currently supported operators are:
     408             :  *
     409             :  * \li NODE_UNKNOWN -- remove the operator
     410             :  * \li NODE_STRICTLY_EQUAL -- "===", this is considered the default
     411             :  *                                   behavior for a JavaScript switch()
     412             :  * \li NODE_EQUAL -- "=="
     413             :  * \li NODE_NOT_EQUAL -- "!="
     414             :  * \li NODE_STRICTLY_NOT_EQUAL -- "!=="
     415             :  * \li NODE_MATCH -- "~="
     416             :  * \li NODE_IN -- "in", this makes use of ranges
     417             :  * \li NODE_IS -- "is"
     418             :  * \li NODE_AS -- "as"
     419             :  * \li NODE_INSTANCEOF -- "instanceof"
     420             :  * \li NODE_LESS -- "<"
     421             :  * \li NODE_LESS_EQUAL -- "<="
     422             :  * \li NODE_GREATER -- ">"
     423             :  * \li NODE_GREATER_EQUAL -- ">="
     424             :  * \li NODE_DEFAULT -- this is the default label case
     425             :  *
     426             :  * \exception exception_internal_error
     427             :  * If the function is called on a node of a type other than NODE_SWITCH
     428             :  * then this exception is raised. It will also raise this exception
     429             :  * if the specified operator is not an operator supported by the
     430             :  * switch statement.
     431             :  *
     432             :  * \param[in] op  The new operator to save in this switch statement.
     433             :  *
     434             :  * \sa get_switch_operator()
     435             :  */
     436       41299 : void Node::set_switch_operator(node_t op)
     437             : {
     438       41299 :     if(node_t::NODE_SWITCH != f_type)
     439             :     {
     440         169 :         throw exception_internal_error("INTERNAL ERROR: set_switch_operator() called on a node which is not a switch node.");
     441             :     }
     442             : 
     443       41130 :     switch(op)
     444             :     {
     445             :     case node_t::NODE_UNKNOWN:
     446             :     case node_t::NODE_STRICTLY_EQUAL:
     447             :     case node_t::NODE_EQUAL:
     448             :     case node_t::NODE_NOT_EQUAL:
     449             :     case node_t::NODE_STRICTLY_NOT_EQUAL:
     450             :     case node_t::NODE_MATCH:
     451             :     case node_t::NODE_IN:
     452             :     case node_t::NODE_IS:
     453             :     case node_t::NODE_AS:
     454             :     case node_t::NODE_INSTANCEOF:
     455             :     case node_t::NODE_LESS:
     456             :     case node_t::NODE_LESS_EQUAL:
     457             :     case node_t::NODE_GREATER:
     458             :     case node_t::NODE_GREATER_EQUAL:
     459             :     case node_t::NODE_DEFAULT:
     460       40975 :         break;
     461             : 
     462             :     default:
     463         155 :         throw exception_internal_error("INTERNAL ERROR: set_switch_operator() called with an operator which is not valid for switch.");
     464             : 
     465             :     }
     466             : 
     467       40975 :     f_switch_operator = op;
     468       40975 : }
     469             : 
     470             : 
     471             : /**********************************************************************/
     472             : /**********************************************************************/
     473             : /***  NODE POSITION  **************************************************/
     474             : /**********************************************************************/
     475             : /**********************************************************************/
     476             : 
     477             : 
     478             : /** \brief Create a new node with the given type.
     479             :  *
     480             :  * This function creates a new node that is expected to be used as a
     481             :  * replacement of this node.
     482             :  *
     483             :  * Note that the input node does not get modified by this call.
     484             :  *
     485             :  * This is similar to creating a node directly and then setting up the
     486             :  * position of the new node to the position information of 'this' node.
     487             :  * In other words, a short hand for this:
     488             :  *
     489             :  * \code
     490             :  *      Node::pointer_t n(new Node(type));
     491             :  *      n->set_position(node->get_position());
     492             :  * \endcode
     493             :  *
     494             :  * \param[in] type  The type of the new node.
     495             :  *
     496             :  * \return A new node pointer.
     497             :  *
     498             :  * \sa set_position()
     499             :  */
     500       59381 : Node::pointer_t Node::create_replacement(node_t type) const
     501             : {
     502             :     // TBD: should we limit the type of replacement nodes?
     503       59381 :     Node::pointer_t n(new Node(type));
     504             : 
     505             :     // this is why we want to have a function instead of doing new Node().
     506       59381 :     n->f_position = f_position;
     507             : 
     508       59381 :     return n;
     509             : }
     510             : 
     511             : 
     512             : /** \brief Change the position of the node.
     513             :  *
     514             :  * As you are reading a file, a position object gets updated. That position
     515             :  * object represents the location where different token are found in the
     516             :  * source files. It is saved in a node as it is created to represent the
     517             :  * position where the data was found. This helps in indicating to the user
     518             :  * where an error occurred.
     519             :  *
     520             :  * The position used as input can later change as the node keeps a copy of
     521             :  * the parameter passed to it.
     522             :  *
     523             :  * The position can later be retrieved with the get_position() function.
     524             :  *
     525             :  * When the compiler creates new nodes as required, it generally will make
     526             :  * use of the create_replacement() function which creates a new node with
     527             :  * a new type, but keeps the position information of the old node.
     528             :  *
     529             :  * \param[in] position  The new position to copy in this node.
     530             :  *
     531             :  * \sa get_position()
     532             :  */
     533    67073903 : void Node::set_position(Position const& position)
     534             : {
     535    67073903 :     f_position = position;
     536    67073903 : }
     537             : 
     538             : 
     539             : /** \brief The position of the node.
     540             :  *
     541             :  * This function returns a reference to the position of the node.
     542             :  * The position represents the filename, line number, character position,
     543             :  * function name, etc. where this specific node was read. It can be used
     544             :  * to print out the line to the user and to show him exactly where the
     545             :  * error occurred.
     546             :  *
     547             :  * This position can be changed with the set_position() function. By
     548             :  * default a node has a default position: no file name, no function name,
     549             :  * and positions are all set to 1.
     550             :  *
     551             :  * \return The position of this node.
     552             :  *
     553             :  * \sa set_position()
     554             :  */
     555      203270 : Position const& Node::get_position() const
     556             : {
     557      203270 :     return f_position;
     558             : }
     559             : 
     560             : 
     561             : /**********************************************************************/
     562             : /**********************************************************************/
     563             : /***  NODE LINK  ******************************************************/
     564             : /**********************************************************************/
     565             : /**********************************************************************/
     566             : 
     567             : 
     568             : /** \brief Save a link in this node.
     569             :  *
     570             :  * This function saves a link pointer in this node. It can later be
     571             :  * retrieved using the get_link() function.
     572             :  *
     573             :  * If a link was already defined at that offset, the function raises
     574             :  * an exception and the existing offset is not modified.
     575             :  *
     576             :  * It is possible to clear a link by passing an empty smart pointer
     577             :  * down (i.e. pass nullptr.) If you first clear a link in this way,
     578             :  * you can then replace it with another pointer.
     579             :  *
     580             :  * \code
     581             :  *     // do not throw because we reset the link first:
     582             :  *     node->set_link(Node::link_t::LINK_TYPE, nullptr);
     583             :  *     node->set_link(Node::link_t::LINK_TYPE, link);
     584             :  * \endcode
     585             :  *
     586             :  * Links are used to save information about a node such as its
     587             :  * type and attributes.
     588             :  *
     589             :  * \note
     590             :  * Links are saved as full smart pointers, not weak pointers. This means
     591             :  * a node that references another in this way may generate loops that
     592             :  * will not easily break when trying to release the whole tree.
     593             :  *
     594             :  * \note
     595             :  * The Node must not be locked.
     596             :  *
     597             :  * \exception exception_index_out_of_range
     598             :  * The index is out of range. Links make use of a very few predefined
     599             :  * indexes such as Node::link_t::LINK_ATTRIBUTES. However,
     600             :  * Node::link_t::LINK_max cannot be used as an index.
     601             :  *
     602             :  * \exception exception_already_defined
     603             :  * The link at that index is already defined and the function was called
     604             :  * anyway. This is an internal error because you should check whether the
     605             :  * value was already defined and if so use that value.
     606             :  *
     607             :  * \param[in] index  The index of the link to save.
     608             :  * \param[in] link  A smart pointer to the link.
     609             :  *
     610             :  * \sa get_link()
     611             :  */
     612      877001 : void Node::set_link(link_t index, pointer_t link)
     613             : {
     614      877001 :     modifying();
     615             : 
     616      877001 :     if(index >= link_t::LINK_max)
     617             :     {
     618         150 :         throw exception_index_out_of_range("set_link() called with an index out of bounds.");
     619             :     }
     620             : 
     621             :     // make sure the size is reserved on first set
     622      876851 :     if(f_link.empty())
     623             :     {
     624      876610 :         f_link.resize(static_cast<vector_of_pointers_t::size_type>(link_t::LINK_max));
     625             :     }
     626             : 
     627      876851 :     if(link)
     628             :     {
     629             :         // link already set?
     630      876801 :         if(f_link[static_cast<size_t>(index)])
     631             :         {
     632         100 :             throw exception_already_defined("a link was set twice at the same offset");
     633             :         }
     634             : 
     635      876701 :         f_link[static_cast<size_t>(index)] = link;
     636             :     }
     637             :     else
     638             :     {
     639          50 :         f_link[static_cast<size_t>(index)].reset();
     640             :     }
     641      876751 : }
     642             : 
     643             : 
     644             : /** \brief Retrieve a link previously saved with set_link().
     645             :  *
     646             :  * This function returns a pointer to a link that was previously
     647             :  * saved in this node using the set_link() function.
     648             :  *
     649             :  * Links are used to save information about a node such as its
     650             :  * type and attributes.
     651             :  *
     652             :  * The function may return a null pointer. You are responsible
     653             :  * for checking the validity of the link.
     654             :  *
     655             :  * \exception exception_index_out_of_range
     656             :  * The index is out of range. Links make use of a very few predefined
     657             :  * indexes such as Node::link_t::LINK_ATTRIBUTES. However,
     658             :  * Node::link_t::LINK_max cannot be used as an index.
     659             :  *
     660             :  * \param[in] index  The index of the link to retrieve.
     661             :  *
     662             :  * \return A smart pointer to this link node.
     663             :  */
     664   119701723 : Node::pointer_t Node::get_link(link_t index)
     665             : {
     666   119701723 :     if(index >= link_t::LINK_max)
     667             :     {
     668         150 :         throw exception_index_out_of_range("get_link() called with an index out of bounds.");
     669             :     }
     670             : 
     671   119701573 :     if(f_link.empty())
     672             :     {
     673   115318763 :         return nullptr;
     674             :     }
     675             : 
     676     4382810 :     return f_link[static_cast<size_t>(index)];
     677             : }
     678             : 
     679             : 
     680             : /**********************************************************************/
     681             : /**********************************************************************/
     682             : /***  NODE VARIABLE  **************************************************/
     683             : /**********************************************************************/
     684             : /**********************************************************************/
     685             : 
     686             : 
     687             : /** \brief Add a variable to this node.
     688             :  *
     689             :  * A node can hold pointers to variable nodes. This is used to
     690             :  * handle variable scopes properly. Note that the \p variable
     691             :  * parameter must be a node of type NODE_VARIABLE.
     692             :  *
     693             :  * \note
     694             :  * This is not an execution environment and as such the variables are
     695             :  * simply added one after another (not sorted, no attempt to later
     696             :  * retrieve variables by name.) This may change in the future though.
     697             :  *
     698             :  * \todo
     699             :  * Add a test of the node type so we can make sure we do not call this
     700             :  * function on nodes that cannot have variables. For that purpose, we
     701             :  * need to know what those types are.
     702             :  *
     703             :  * \exception exception_incompatible_node_type
     704             :  * This exception is raised if the \p variable parameter is not of type
     705             :  * NODE_VARIABLE.
     706             :  *
     707             :  * \param[in] variable  The variable to be added.
     708             :  *
     709             :  * \sa get_variable()
     710             :  * \sa get_variable_size()
     711             :  */
     712         111 : void Node::add_variable(pointer_t variable)
     713             : {
     714         111 :     if(node_t::NODE_VARIABLE != variable->f_type)
     715             :     {
     716          10 :         throw exception_incompatible_node_type("the variable parameter of the add_variable() function must be a NODE_VARIABLE");
     717             :     }
     718             :     // TODO: test the destination (i.e. this) to make sure only valid nodes
     719             :     //       accept variables; make it a separate function as all the
     720             :     //       variable functions should call it!
     721             : 
     722         101 :     f_variables.push_back(variable);
     723         101 : }
     724             : 
     725             : 
     726             : /** \brief Retrieve the number of variables defined in this node.
     727             :  *
     728             :  * A node can hold variable pointers. This is used to handle variable
     729             :  * scopes properly.
     730             :  *
     731             :  * \todo
     732             :  * Add a test of the node type so we can make sure we do not call this
     733             :  * function on nodes that cannot have variables.
     734             :  *
     735             :  * \return The number of variables currently held in this node.
     736             :  *
     737             :  * \sa add_variable()
     738             :  * \sa get_variable()
     739             :  */
     740      709120 : size_t Node::get_variable_size() const
     741             : {
     742      709120 :     return f_variables.size();
     743             : }
     744             : 
     745             : 
     746             : /** \brief Retrieve the variable at the specified index.
     747             :  *
     748             :  * This function retrieves the variable at the specified index. If the
     749             :  * index is out of the variable array bounds, then the function raises
     750             :  * an error.
     751             :  *
     752             :  * The current boundaries are from 0 to get_variable_size() - 1. This
     753             :  * set may be empty if no variables were added to this node.
     754             :  *
     755             :  * This function will not return a null pointer. An index out of range
     756             :  * raises an exception instead.
     757             :  *
     758             :  * \todo
     759             :  * Add a test of the node type so we can make sure we do not call this
     760             :  * function on nodes that cannot have variables.
     761             :  *
     762             :  * \param[in] index  The index of the variable to retrieve.
     763             :  *
     764             :  * \return A pointer to the specified variable.
     765             :  *
     766             :  * \sa add_variable()
     767             :  * \sa get_variable_size()
     768             :  */
     769         200 : Node::pointer_t Node::get_variable(int index) const
     770             : {
     771         200 :     return f_variables.at(index);
     772             : }
     773             : 
     774             : 
     775             : /**********************************************************************/
     776             : /**********************************************************************/
     777             : /***  NODE LABEL  *****************************************************/
     778             : /**********************************************************************/
     779             : /**********************************************************************/
     780             : 
     781             : 
     782             : /** \brief Add a label to a function.
     783             :  *
     784             :  * This function adds a label to this function node. Labels are saved
     785             :  * using a map so we can quickly find them.
     786             :  *
     787             :  * \note
     788             :  * After a label was added to a function, its name should never get
     789             :  * modified or it will be out of synchronization with the function.
     790             :  *
     791             :  * \exception exception_incompatible_node_type
     792             :  * If this function is called with objects other than a NODE_LABEL
     793             :  * as the label parameter and a NODE_FUNCTION as 'this' parameter,
     794             :  * then this exception is raised.
     795             :  *
     796             :  * \exception exception_incompatible_node_data
     797             :  * If the node representing the label does not have a valid string
     798             :  * attached to it (i.e. if it is empty) then this exception is
     799             :  * raised.
     800             :  *
     801             :  * \exception exception_already_defined
     802             :  * If the label was already defined, then this exception is raised.
     803             :  * Within one function each label must be unique, however, sub-functions
     804             :  * have their own scope and thus can be a label with the same name as
     805             :  * a label in their parent function.
     806             :  *
     807             :  * \param[in] label  A smart pointer to the label node to add.
     808             :  *
     809             :  * \sa find_label()
     810             :  */
     811         411 : void Node::add_label(pointer_t label)
     812             : {
     813         822 :     if(node_t::NODE_LABEL != label->f_type
     814         411 :     || node_t::NODE_FUNCTION != f_type)
     815             :     {
     816         110 :         throw exception_incompatible_node_type("invalid type of node to call add_label() with");
     817             :     }
     818         301 :     if(label->f_str.empty())
     819             :     {
     820         100 :         throw exception_incompatible_node_data("a label without a valid name cannot be added to a function");
     821             :     }
     822         201 :     if(f_labels.find(label->f_str) != f_labels.end())
     823             :     {
     824         100 :         throw exception_already_defined("a label with the same name is already defined in this function.");
     825             :     }
     826             : 
     827         101 :     f_labels[label->f_str] = label;
     828         101 : }
     829             : 
     830             : 
     831             : /** \brief Find a label previously added with the add_label() function.
     832             :  *
     833             :  * This function checks whether a label was defined in this function. If
     834             :  * so, then its smart pointer gets returned.
     835             :  *
     836             :  * The \p name parameter represents the name of the label exactly. The
     837             :  * returned label will have the same name.
     838             :  *
     839             :  * \param[in] name  The name of the label to retrieve.
     840             :  *
     841             :  * \return A pointer to the label if it exists, a null pointer otherwise.
     842             :  *
     843             :  * \sa add_label()
     844             :  */
     845         100 : Node::pointer_t Node::find_label(String const& name) const
     846             : {
     847         100 :     map_of_pointers_t::const_iterator it(f_labels.find(name));
     848         100 :     return it == f_labels.end() ? pointer_t() : it->second;
     849             : }
     850             : 
     851             : 
     852             : 
     853             : 
     854          63 : }
     855             : // namespace as2js
     856             : 
     857             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10