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

          Line data    Source code
       1             : /* node_tree.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             : #include    <algorithm>
      41             : 
      42             : 
      43             : /** \file
      44             :  * \brief Handle the node tree.
      45             :  *
      46             :  * This file includes the implementation of the various
      47             :  * functions used to handle the tree of nodes.
      48             :  *
      49             :  * The main function is the set_parent() function, which is
      50             :  * used to manage the tree (parent/children relationships).
      51             :  *
      52             :  * Most of the other functions call the set_parent() function
      53             :  * after some verifications and with the parameters as
      54             :  * expected.
      55             :  *
      56             :  * Note that all nodes are expected to live in a tree. There
      57             :  * are some cases when one node has more than one list of
      58             :  * children. These are the links and variables as defined
      59             :  * by their respective function implementations. Those are
      60             :  * not handled in the tree, instead the Node object includes
      61             :  * another set of Node::pointer_t arrays to handle those
      62             :  * special cases.
      63             :  *
      64             :  * The parent reference is a weak pointer. This allows a
      65             :  * parent to get rid of a child without too much work.
      66             :  */
      67             : 
      68             : 
      69             : namespace as2js
      70             : {
      71             : 
      72             : 
      73             : 
      74             : /**********************************************************************/
      75             : /**********************************************************************/
      76             : /***  NODE TREE  ******************************************************/
      77             : /**********************************************************************/
      78             : /**********************************************************************/
      79             : 
      80             : 
      81             : 
      82             : /** \brief This function sets the parent of a node.
      83             :  *
      84             :  * This function is the only function that handles the tree of nodes,
      85             :  * in other words, the only one that modifies the f_parent and
      86             :  * f_children pointers. It is done that way to make 100% sure (assuming
      87             :  * it is itself correct) that we do not mess up the tree.
      88             :  *
      89             :  * This node loses its current parent, and thus is removed from the
      90             :  * list of children of that parent. Then is is assigned the new
      91             :  * parent as passed to this function.
      92             :  *
      93             :  * If an \p index is specified, the child is inserted at that specific
      94             :  * location. Otherwise the child is appended.
      95             :  *
      96             :  * The function does nothing if the current parent is the same as the
      97             :  * new parent and the default \p index is used (-1).
      98             :  *
      99             :  * Use an \p index of 0 to insert the item at the start of the list
     100             :  * of children. Use an \p index of get_children_size() to force the
     101             :  * child at the end of the list even if the parent remains the same.
     102             :  *
     103             :  * Helper functions are available to make more sense of the usage of
     104             :  * this function but they all are based on the set_parent() function:
     105             :  *
     106             :  * \li delete_child() -- delete a child at that specific index.
     107             :  * \li append_child() -- append a child to this parent.
     108             :  * \li insert_child() -- insert a child to this parent.
     109             :  * \li set_child() -- replace a child with another in this parent.
     110             :  * \li replace_with() -- replace a child with another not knowing its offset.
     111             :  *
     112             :  * \note
     113             :  * This Node and the \p parent Node must not be locked.
     114             :  * If the parent is being changed, then the other existing parent
     115             :  * must also not be locked either.
     116             :  *
     117             :  * \note
     118             :  * The vector of children of the parent node changes, be careful.
     119             :  * Whenever possible, to avoid bugs, you may want to consider using
     120             :  * the lock() function through the NodeLock object to avoid having
     121             :  * such changes happen on nodes you are currently working on.
     122             :  *
     123             :  * \exception exception_incompatible_node_type
     124             :  * The parent must be a node of a type which is compatible with
     125             :  * being a parent. We actually limit the type to exactly and just
     126             :  * and only the types of nodes that receive children. For example,
     127             :  * a NODE_INT64 cannot receive children. Trying to add a child
     128             :  * to such a node raises this exception. Similarly, some nodes,
     129             :  * such as NODE_CLOSE_PARENTHESIS, cannot be children of another.
     130             :  * The same exception is raised if such a node receives a parent.
     131             :  *
     132             :  * \exception exception_internal_error
     133             :  * When the Node already had a parent and it gets replaced, we
     134             :  * have to remove that existing parent first. This exception is
     135             :  * raised if we cannot find this Node in the list of children of
     136             :  * the existing parent.
     137             :  *
     138             :  * \exception exception_index_out_of_range
     139             :  * If the \p index parameter is larger than the number of children
     140             :  * currently available in the new parent or is negative, then this
     141             :  * exception is raised. Note that if the index is -1, then the
     142             :  * correct value is used to append the child.
     143             :  *
     144             :  * \param[in] parent  The new parent of the node. May be set to nullptr.
     145             :  * \param[in] index  The position where the new item is inserted in the parent
     146             :  *                   array of children. If -1, append at the end of the list.
     147             :  *
     148             :  * \sa lock()
     149             :  * \sa get_parent()
     150             :  * \sa get_children_size()
     151             :  * \sa delete_child()
     152             :  * \sa append_child()
     153             :  * \sa insert_child()
     154             :  * \sa set_child()
     155             :  * \sa replace_with()
     156             :  * \sa get_child()
     157             :  * \sa find_first_child()
     158             :  * \sa find_next_child()
     159             :  * \sa clean_tree()
     160             :  * \sa get_offset()
     161             :  */
     162    23900291 : void Node::set_parent(pointer_t parent, int index)
     163             : {
     164             :     // we are modifying the child and both parents
     165    23900291 :     modifying();
     166             : 
     167    23900290 :     if(parent)
     168             :     {
     169    23006729 :         parent->modifying();
     170             :     }
     171             : 
     172    23900290 :     Node::pointer_t p(f_parent.lock());
     173    23900290 :     if(parent != p && p)
     174             :     {
     175      893898 :         p->modifying();
     176             :     }
     177             : 
     178             :     // already a child of that parent?
     179             :     // (although in case of an insert, we force the re-parent
     180             :     // to the right location)
     181    23900290 :     if(parent == p && index == -1)
     182             :     {
     183    23890386 :         return;
     184             :     }
     185             : 
     186             :     // tests to make sure that the parent accepts children
     187             :     // (if we got a parent pointer)
     188    23900290 :     if(parent) switch(parent->get_type())
     189             :     {
     190             :     case node_t::NODE_UNKNOWN: // this can be anything so we keep it here
     191             :     case node_t::NODE_ADD:
     192             :     case node_t::NODE_BITWISE_AND:
     193             :     case node_t::NODE_BITWISE_NOT:
     194             :     case node_t::NODE_ASSIGNMENT:
     195             :     case node_t::NODE_BITWISE_OR:
     196             :     case node_t::NODE_BITWISE_XOR:
     197             :     case node_t::NODE_CONDITIONAL:
     198             :     case node_t::NODE_DIVIDE:
     199             :     case node_t::NODE_GREATER:
     200             :     case node_t::NODE_LESS:
     201             :     case node_t::NODE_LOGICAL_NOT:
     202             :     case node_t::NODE_MODULO:
     203             :     case node_t::NODE_MULTIPLY:
     204             :     case node_t::NODE_MEMBER:
     205             :     case node_t::NODE_SUBTRACT:
     206             :     case node_t::NODE_ARRAY:
     207             :     case node_t::NODE_ARRAY_LITERAL:
     208             :     case node_t::NODE_AS:
     209             :     case node_t::NODE_ASSIGNMENT_ADD:
     210             :     case node_t::NODE_ASSIGNMENT_BITWISE_AND:
     211             :     case node_t::NODE_ASSIGNMENT_BITWISE_OR:
     212             :     case node_t::NODE_ASSIGNMENT_BITWISE_XOR:
     213             :     case node_t::NODE_ASSIGNMENT_DIVIDE:
     214             :     case node_t::NODE_ASSIGNMENT_LOGICAL_AND:
     215             :     case node_t::NODE_ASSIGNMENT_LOGICAL_OR:
     216             :     case node_t::NODE_ASSIGNMENT_LOGICAL_XOR:
     217             :     case node_t::NODE_ASSIGNMENT_MAXIMUM:
     218             :     case node_t::NODE_ASSIGNMENT_MINIMUM:
     219             :     case node_t::NODE_ASSIGNMENT_MODULO:
     220             :     case node_t::NODE_ASSIGNMENT_MULTIPLY:
     221             :     case node_t::NODE_ASSIGNMENT_POWER:
     222             :     case node_t::NODE_ASSIGNMENT_ROTATE_LEFT:
     223             :     case node_t::NODE_ASSIGNMENT_ROTATE_RIGHT:
     224             :     case node_t::NODE_ASSIGNMENT_SHIFT_LEFT:
     225             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT:
     226             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
     227             :     case node_t::NODE_ASSIGNMENT_SUBTRACT:
     228             :     case node_t::NODE_ATTRIBUTES:
     229             :     case node_t::NODE_CALL:
     230             :     case node_t::NODE_CASE:
     231             :     case node_t::NODE_CATCH:
     232             :     case node_t::NODE_CLASS:
     233             :     case node_t::NODE_COMPARE:
     234             :     case node_t::NODE_DEBUGGER:
     235             :     case node_t::NODE_DECREMENT:
     236             :     case node_t::NODE_DELETE:
     237             :     case node_t::NODE_DIRECTIVE_LIST:
     238             :     case node_t::NODE_DO:
     239             :     case node_t::NODE_ENSURE:
     240             :     case node_t::NODE_ENUM:
     241             :     case node_t::NODE_EQUAL:
     242             :     case node_t::NODE_EXCLUDE:
     243             :     case node_t::NODE_EXPORT:
     244             :     case node_t::NODE_EXTENDS:
     245             :     case node_t::NODE_FINALLY:
     246             :     case node_t::NODE_FOR:
     247             :     case node_t::NODE_FUNCTION:
     248             :     case node_t::NODE_GREATER_EQUAL:
     249             :     case node_t::NODE_IF:
     250             :     case node_t::NODE_IMPLEMENTS:
     251             :     case node_t::NODE_IMPORT:
     252             :     case node_t::NODE_IN:
     253             :     case node_t::NODE_INCLUDE:
     254             :     case node_t::NODE_INCREMENT:
     255             :     case node_t::NODE_INSTANCEOF:
     256             :     case node_t::NODE_INTERFACE:
     257             :     case node_t::NODE_INVARIANT:
     258             :     case node_t::NODE_IS:
     259             :     case node_t::NODE_LABEL:
     260             :     case node_t::NODE_LESS_EQUAL:
     261             :     case node_t::NODE_LIST:
     262             :     case node_t::NODE_LOGICAL_AND:
     263             :     case node_t::NODE_LOGICAL_OR:
     264             :     case node_t::NODE_LOGICAL_XOR:
     265             :     case node_t::NODE_MATCH:
     266             :     case node_t::NODE_MAXIMUM:
     267             :     case node_t::NODE_MINIMUM:
     268             :     case node_t::NODE_NAME:
     269             :     case node_t::NODE_NAMESPACE:
     270             :     case node_t::NODE_NEW:
     271             :     case node_t::NODE_NOT_EQUAL:
     272             :     case node_t::NODE_NOT_MATCH:
     273             :     case node_t::NODE_OBJECT_LITERAL:
     274             :     case node_t::NODE_PACKAGE:
     275             :     case node_t::NODE_PARAM:
     276             :     case node_t::NODE_PARAMETERS:
     277             :     case node_t::NODE_PARAM_MATCH:
     278             :     case node_t::NODE_POST_DECREMENT:
     279             :     case node_t::NODE_POST_INCREMENT:
     280             :     case node_t::NODE_POWER:
     281             :     case node_t::NODE_PROGRAM:
     282             :     case node_t::NODE_RANGE:
     283             :     case node_t::NODE_REQUIRE:
     284             :     case node_t::NODE_RETURN:
     285             :     case node_t::NODE_ROOT:
     286             :     case node_t::NODE_ROTATE_LEFT:
     287             :     case node_t::NODE_ROTATE_RIGHT:
     288             :     case node_t::NODE_SCOPE:
     289             :     case node_t::NODE_SET:
     290             :     case node_t::NODE_SHIFT_LEFT:
     291             :     case node_t::NODE_SHIFT_RIGHT:
     292             :     case node_t::NODE_SHIFT_RIGHT_UNSIGNED:
     293             :     case node_t::NODE_SMART_MATCH:
     294             :     case node_t::NODE_STRICTLY_EQUAL:
     295             :     case node_t::NODE_STRICTLY_NOT_EQUAL:
     296             :     case node_t::NODE_SUPER:
     297             :     case node_t::NODE_SWITCH:
     298             :     case node_t::NODE_SYNCHRONIZED:
     299             :     case node_t::NODE_THROW:
     300             :     case node_t::NODE_THROWS:
     301             :     case node_t::NODE_TRY:
     302             :     case node_t::NODE_TYPE:
     303             :     case node_t::NODE_TYPEOF:
     304             :     case node_t::NODE_USE:
     305             :     case node_t::NODE_VAR:
     306             :     case node_t::NODE_VARIABLE:
     307             :     case node_t::NODE_VAR_ATTRIBUTES:
     308             :     case node_t::NODE_WHILE:
     309             :     case node_t::NODE_WITH:
     310             :     case node_t::NODE_YIELD:
     311    22998399 :         break;
     312             : 
     313             :     // All those node types are assumed to never support a child
     314             :     case node_t::NODE_ABSTRACT:
     315             :     case node_t::NODE_AUTO:
     316             :     case node_t::NODE_BOOLEAN:
     317             :     case node_t::NODE_BREAK:
     318             :     case node_t::NODE_BYTE:
     319             :     case node_t::NODE_CHAR:
     320             :     case node_t::NODE_CLOSE_CURVLY_BRACKET:
     321             :     case node_t::NODE_CLOSE_PARENTHESIS:
     322             :     case node_t::NODE_CLOSE_SQUARE_BRACKET:
     323             :     case node_t::NODE_COLON:
     324             :     case node_t::NODE_COMMA:
     325             :     case node_t::NODE_CONST:
     326             :     case node_t::NODE_CONTINUE:
     327             :     case node_t::NODE_DEFAULT:
     328             :     case node_t::NODE_DOUBLE:
     329             :     case node_t::NODE_ELSE:
     330             :     case node_t::NODE_EMPTY:
     331             :     case node_t::NODE_EOF:
     332             :     case node_t::NODE_FINAL:
     333             :     case node_t::NODE_FLOAT:
     334             :     case node_t::NODE_IDENTIFIER:
     335             :     case node_t::NODE_INLINE:
     336             :     case node_t::NODE_INT64:
     337             :     case node_t::NODE_FALSE:
     338             :     case node_t::NODE_FLOAT64:
     339             :     case node_t::NODE_GOTO:
     340             :     case node_t::NODE_LONG:
     341             :     case node_t::NODE_NATIVE:
     342             :     case node_t::NODE_NULL:
     343             :     case node_t::NODE_OPEN_CURVLY_BRACKET:
     344             :     case node_t::NODE_OPEN_PARENTHESIS:
     345             :     case node_t::NODE_OPEN_SQUARE_BRACKET:
     346             :     case node_t::NODE_PRIVATE:
     347             :     case node_t::NODE_PROTECTED:
     348             :     case node_t::NODE_PUBLIC:
     349             :     case node_t::NODE_REGULAR_EXPRESSION:
     350             :     case node_t::NODE_REST:
     351             :     case node_t::NODE_SEMICOLON:
     352             :     case node_t::NODE_SHORT:
     353             :     case node_t::NODE_STATIC:
     354             :     case node_t::NODE_STRING:
     355             :     case node_t::NODE_THEN:
     356             :     case node_t::NODE_THIS:
     357             :     case node_t::NODE_TRANSIENT:
     358             :     case node_t::NODE_TRUE:
     359             :     case node_t::NODE_UNDEFINED:
     360             :     case node_t::NODE_VIDENTIFIER:
     361             :     case node_t::NODE_VOID:
     362             :     case node_t::NODE_VOLATILE:
     363             :     case node_t::NODE_other:        // for completeness
     364             :     case node_t::NODE_max:          // for completeness
     365             :         // ERROR: some values are not valid as a type
     366        8330 :         throw exception_incompatible_node_type("invalid type used as a parent node");
     367             : 
     368             :     }
     369             : 
     370             :     // verify that 'this' can be a child
     371    23891960 :     switch(f_type)
     372             :     {
     373             :     case node_t::NODE_CLOSE_CURVLY_BRACKET:
     374             :     case node_t::NODE_CLOSE_PARENTHESIS:
     375             :     case node_t::NODE_CLOSE_SQUARE_BRACKET:
     376             :     case node_t::NODE_COLON:
     377             :     case node_t::NODE_COMMA:
     378             :     case node_t::NODE_ELSE:
     379             :     case node_t::NODE_THEN:
     380             :     case node_t::NODE_EOF:
     381             :     case node_t::NODE_OPEN_CURVLY_BRACKET:
     382             :     case node_t::NODE_OPEN_PARENTHESIS:
     383             :     case node_t::NODE_OPEN_SQUARE_BRACKET:
     384             :     case node_t::NODE_ROOT: // correct?
     385             :     case node_t::NODE_SEMICOLON:
     386             :     case node_t::NODE_other:        // for completeness
     387             :     case node_t::NODE_max:          // for completeness
     388        1573 :         throw exception_incompatible_node_type("invalid type used as a child node");
     389             : 
     390             :     default:
     391             :         // all others can be children (i.e. most everything)
     392    23890387 :         break;
     393             : 
     394             :     }
     395             : 
     396    23890387 :     if(p)
     397             :     {
     398             :         // very similar to the get_offset() call only we want the iterator
     399             :         // in this case, not the index
     400      893900 :         pointer_t me(shared_from_this());
     401      893900 :         vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
     402      893900 :         if(it == p->f_children.end())
     403             :         {
     404             :             throw exception_internal_error("trying to remove a child from a parent which does not know about that child"); // LCOV_EXCL_LINE
     405             :         }
     406      893900 :         p->f_children.erase(it);
     407      893900 :         f_parent.reset();
     408             :     }
     409             : 
     410    23890387 :     if(parent)
     411             :     {
     412    22996826 :         if(index == -1)
     413             :         {
     414    22996251 :             parent->f_children.push_back(shared_from_this());
     415             :         }
     416             :         else
     417             :         {
     418         575 :             if(static_cast<size_t>(index) > parent->f_children.size())
     419             :             {
     420           1 :                 throw exception_index_out_of_range("trying to insert a node at the wrong position");
     421             :             }
     422         574 :             parent->f_children.insert(parent->f_children.begin() + index, shared_from_this());
     423             :         }
     424    22996825 :         f_parent = parent;
     425    23900290 :     }
     426             : }
     427             : 
     428             : 
     429             : /** \brief Get a pointer to the parent of this node.
     430             :  *
     431             :  * This function returns the pointer to the parent of this node. It may be
     432             :  * a null pointer.
     433             :  *
     434             :  * Note that the parent is kept as a weak pointer internally. However, when
     435             :  * returned it gets locked first (as in shared pointer lock) so you do not
     436             :  * have to do that yourselves.
     437             :  *
     438             :  * \return A smart pointer to the parent node, may be null.
     439             :  *
     440             :  * \sa set_parent()
     441             :  */
     442      744951 : Node::pointer_t Node::get_parent() const
     443             : {
     444      744951 :     return f_parent.lock();
     445             : }
     446             : 
     447             : 
     448             : /** \brief Return the number of children available in this node.
     449             :  *
     450             :  * This function returns the number of children we have available in this
     451             :  * node.
     452             :  *
     453             :  * \return The number of children, may be zero.
     454             :  *
     455             :  * \sa set_parent()
     456             :  */
     457    32275451 : size_t Node::get_children_size() const
     458             : {
     459    32275451 :     return f_children.size();
     460             : }
     461             : 
     462             : 
     463             : /** \brief Delete the specified child from the parent.
     464             :  *
     465             :  * This function removes a child from its parent (i.e. "unparent" a
     466             :  * node.)
     467             :  *
     468             :  * The following two lines of code are identical:
     469             :  *
     470             :  * \code
     471             :  *     parent->delete_child(index);
     472             :  *     // or
     473             :  *     parent->set_parent(nullptr, index);
     474             :  * \endcode
     475             :  *
     476             :  * Note that the vector of children of 'this' node changes, be careful.
     477             :  * Whenever possible, to avoid bugs, you may want to consider using
     478             :  * the lock() function through the NodeLock object.
     479             :  *
     480             :  * \note
     481             :  * The child node being "deleted" is not actively deleted. That is, if
     482             :  * anyone still holds a shared pointer of that node, it will not actually
     483             :  * get deleted. If that was the last shared pointer holding that node,
     484             :  * then it gets deleted automatically by the smart pointer implementation.
     485             :  *
     486             :  * \param[in] index  The index of the child node to remove from 'this' node.
     487             :  *
     488             :  * \sa lock()
     489             :  * \sa set_parent()
     490             :  */
     491      893558 : void Node::delete_child(int index)
     492             : {
     493      893559 :     f_children.at(index)->set_parent();
     494      893557 : }
     495             : 
     496             : 
     497             : /** \brief Append a child to 'this' node.
     498             :  *
     499             :  * This function appends (adds at the end of the vector of children) a
     500             :  * child to 'this' node, which means the child is given 'this'
     501             :  * node as a parent.
     502             :  *
     503             :  * The following two lines of code are identical:
     504             :  *
     505             :  * \code
     506             :  *     parent->append_child(child);
     507             :  *     // or
     508             :  *     child->set_parent(parent);
     509             :  * \endcode
     510             :  *
     511             :  * \exception exception_invalid_data
     512             :  * This function verifies that the \p child pointer is not null. If null,
     513             :  * this exception is raised.
     514             :  *
     515             :  * \param[in] child  The child to be added at the end of 'this' vector
     516             :  *                   of children.
     517             :  *
     518             :  * \sa set_parent()
     519             :  */
     520    22991665 : void Node::append_child(pointer_t child)
     521             : {
     522    22991665 :     if(!child)
     523             :     {
     524           1 :         throw exception_invalid_data("cannot append a child if its pointer is null");
     525             :     }
     526    22996531 :     child->set_parent(shared_from_this());
     527    22986797 : }
     528             : 
     529             : 
     530             : /** \brief Insert the specified child at the specified location.
     531             :  *
     532             :  * When adding a child to a node, it can be placed before existing
     533             :  * children of that node. This function is used for this purpose.
     534             :  *
     535             :  * By default the index is set to -1 which means that the child is
     536             :  * added at the end of the list (see also the append_child() function.)
     537             :  *
     538             :  * This is a helper function since you could as well call the set_parent()
     539             :  * function directly:
     540             :  *
     541             :  * \code
     542             :  *     parent->insert_child(index, child);
     543             :  *     // or
     544             :  *     child->set_parent(parent, index);
     545             :  * \endcode
     546             :  *
     547             :  * \exception exception_invalid_data
     548             :  * This function verifies that the \p child pointer is not null. If null,
     549             :  * this exception is raised.
     550             :  *
     551             :  * \param[in] index  The index where the child will be inserted.
     552             :  * \param[in,out] child  The child to insert at that index.
     553             :  *
     554             :  * \sa set_parent()
     555             :  */
     556         578 : void Node::insert_child(int index, pointer_t child)
     557             : {
     558         578 :     if(!child)
     559             :     {
     560           1 :         throw exception_invalid_data("cannot insert a child if its pointer is null");
     561             :     }
     562         578 :     child->set_parent(shared_from_this(), index);
     563         576 : }
     564             : 
     565             : 
     566             : /** \brief Replace the current child at position \p index with \p child.
     567             :  *
     568             :  * This function replaces the child in this node at \p index with
     569             :  * the new specified \p child.
     570             :  *
     571             :  * This is a helper function as this functionality is offered by
     572             :  * the set_parent() function as in:
     573             :  *
     574             :  * \code
     575             :  *     parent->set_child(index, child);
     576             :  *     // or
     577             :  *     parent->set_parent(nullptr, index);
     578             :  *     child->set_parent(index, parent);
     579             :  * \endcode
     580             :  *
     581             :  * \exception exception_invalid_data
     582             :  * This function verifies that the \p child pointer is not null. If null,
     583             :  * this exception is raised.
     584             :  *
     585             :  * \param[in] index  The position where the new child is to be placed.
     586             :  * \param[in,out] child  The new child replacing the existing child at \p index.
     587             :  *
     588             :  * \sa set_parent()
     589             :  */
     590         570 : void Node::set_child(int index, pointer_t child)
     591             : {
     592             :     // to respect the contract, we have to test child here too
     593         570 :     if(!child)
     594             :     {
     595           1 :         throw exception_invalid_data("cannot insert a child if its pointer is null");
     596             :     }
     597         569 :     delete_child(index);
     598         569 :     insert_child(index, child);
     599         569 : }
     600             : 
     601             : 
     602             : /** \brief Replace this node with the \p node parameter.
     603             :  *
     604             :  * This function replaces this node with the specified node. This is used
     605             :  * in the optimizer and in the compiler.
     606             :  *
     607             :  * It is useful in a case such as an if() statement that has a resulting
     608             :  * Boolean value known at compile time. For example:
     609             :  *
     610             :  * \code
     611             :  *  if(true)
     612             :  *      blah;
     613             :  *  else
     614             :  *      foo;
     615             :  * \endcode
     616             :  *
     617             :  * can be optimized by just this:
     618             :  *
     619             :  * \code
     620             :  *  blah;
     621             :  * \endcode
     622             :  *
     623             :  * In that case what we do is replace the NODE_IF (this) with the content
     624             :  * of the 'blah' node. This can be done with this function.
     625             :  *
     626             :  * This function is very similar to the set_child() when you do not know
     627             :  * the index position of 'this' node in its parent or do not have the
     628             :  * parent node handy. The following code shows what the function does
     629             :  * internally (without all the additional checks):
     630             :  *
     631             :  * \code
     632             :  *     child->replace_with(node);
     633             :  *     // or
     634             :  *     int index(child->get_offset());
     635             :  *     Node::pointer_t parent(child->get_parent());
     636             :  *     parent->set_child(index, node);
     637             :  * \endcode
     638             :  *
     639             :  * \warning
     640             :  * This function modifies the tree in a way that may break loops over
     641             :  * node children.
     642             :  *
     643             :  * \exception exception_no_parent
     644             :  * If 'this' node does not have a parent node, then this exception is
     645             :  * raised.
     646             :  *
     647             :  * \param[in] node  The node to replace 'this' node with.
     648             :  *
     649             :  * \sa set_parent()
     650             :  */
     651         565 : void Node::replace_with(pointer_t node)
     652             : {
     653             :     // to respect the contract, we have to test child here too
     654         565 :     if(!node)
     655             :     {
     656           1 :         throw exception_invalid_data("cannot replace with a node if its pointer is null");
     657             :     }
     658         564 :     pointer_t p(f_parent.lock());
     659         564 :     if(!p)
     660             :     {
     661           1 :         throw exception_no_parent("trying to replace a node which has no parent");
     662             :     }
     663         563 :     p->set_child(get_offset(), node);
     664         563 : }
     665             : 
     666             : 
     667             : /** \brief Retrieve a child.
     668             :  *
     669             :  * This function retrieves a child from this parent node.
     670             :  *
     671             :  * The \p index parameter must be between 0 and get_children_size() - 1.
     672             :  * If get_children_size() returns zero, then you cannot call this function.
     673             :  *
     674             :  * \exception std::out_of_range
     675             :  * If the index is out of bounds, the function throws this exception.
     676             :  *
     677             :  * \param[in] index  The index of the child to retrieve.
     678             :  *
     679             :  * \return A shared pointer to the specified child.
     680             :  *
     681             :  * \sa set_parent()
     682             :  * \sa get_parent()
     683             :  * \sa get_children_size()
     684             :  */
     685    23111500 : Node::pointer_t Node::get_child(int index) const
     686             : {
     687    23111500 :     return f_children.at(index);
     688             : }
     689             : 
     690             : 
     691             : /** \brief Find the first child of a given type.
     692             :  *
     693             :  * This function searches the vector of children for the first child
     694             :  * with the specified \p type. This can be used to quickly scan a
     695             :  * list of children for the first node with a specific type.
     696             :  *
     697             :  * \note
     698             :  * This function calls the find_next_child() with a null pointer in
     699             :  * the child parameter.
     700             :  *
     701             :  * \code
     702             :  *      find_next_child(nullptr, type);
     703             :  * \endcode
     704             :  *
     705             :  * \param[in] type  The type of nodes you are interested in.
     706             :  *
     707             :  * \return A pointer to the first node of that type or a null pointer.
     708             :  *
     709             :  * \sa find_next_child()
     710             :  */
     711       18997 : Node::pointer_t Node::find_first_child(node_t type) const
     712             : {
     713       18997 :     Node::pointer_t child;
     714       18997 :     return find_next_child(child, type);
     715             : }
     716             : 
     717             : 
     718             : /** \brief Find the next child with the specified type.
     719             :  *
     720             :  * This function searches the vector of children for the next child
     721             :  * with the specified \p type. This can be used to quickly scan a
     722             :  * list of children for a specific type of node.
     723             :  *
     724             :  * The \p child parameter can be set to nullptr in which case the
     725             :  * first child of that type is returned (like find_first_child()
     726             :  * would do for you.)
     727             :  *
     728             :  * \bug
     729             :  * If you have to manage all the nodes of a given type in a large
     730             :  * list, it is wise to create your own loop because this loop
     731             :  * restarts from index zero every single time. This should get
     732             :  * fixed in a future release, although I am not so sure there a
     733             :  * way to do that without a context.
     734             :  *
     735             :  * \param[in] child  A pointer to the previously returned child node.
     736             :  * \param[in] type  The type of children to look for.
     737             :  *
     738             :  * \return The next child of that type or a null pointer.
     739             :  *
     740             :  * \sa find_first_child()
     741             :  */
     742       37994 : Node::pointer_t Node::find_next_child(pointer_t child, node_t type) const
     743             : {
     744       37994 :     size_t const max(f_children.size());
     745     3020523 :     for(size_t idx(0); idx < max; ++idx)
     746             :     {
     747             :         // if child is defined, skip up to it first
     748     3001526 :         if(child && child == f_children[idx])
     749             :         {
     750       18997 :             child.reset();
     751             :         }
     752     2982529 :         else if(f_children[idx]->get_type() == type)
     753             :         {
     754       18997 :             return f_children[idx];
     755             :         }
     756             :     }
     757             : 
     758             :     // not found...
     759       18997 :     return pointer_t();
     760             : }
     761             : 
     762             : 
     763             : /** \brief Remove all the unknown nodes.
     764             :  *
     765             :  * This function goes through the entire tree starting at 'this' node
     766             :  * and remove all the children that are marked as NODE_UNKNOWN.
     767             :  *
     768             :  * This allows many functions to clear out many nodes without
     769             :  * having to have very special handling of their loops while
     770             :  * scanning all the children of a node.
     771             :  *
     772             :  * \note
     773             :  * The nodes themselves do not get deleted by this function. If
     774             :  * it was their last reference then it will be deleted by the
     775             :  * shared pointer code as expected.
     776             :  *
     777             :  * \sa set_parent()
     778             :  * \sa delete_child()
     779             :  */
     780       34184 : void Node::clean_tree()
     781             : {
     782       34184 :     size_t idx(f_children.size());
     783       93935 :     while(idx > 0)
     784             :     {
     785       25571 :         --idx;
     786       25571 :         if(f_children[idx]->get_type() == node_t::NODE_UNKNOWN)
     787             :         {
     788             :             // a delete is automatically recursive
     789           4 :             delete_child(idx);
     790             :         }
     791             :         else
     792             :         {
     793       25567 :             f_children[idx]->clean_tree();  // recursive
     794             :         }
     795             :     }
     796       34180 : }
     797             : 
     798             : 
     799             : /** \brief Find the offset of this node in its parent array of children.
     800             :  *
     801             :  * This function searches for a node in its parent list of children and
     802             :  * returns the corresponding index so we can apply functions to that
     803             :  * child from the parent.
     804             :  *
     805             :  * \exception exception_no_parent
     806             :  * This exception is raised if this Node object does not have a parent.
     807             :  *
     808             :  * \exception exception_internal_error
     809             :  * This exception is raised if the node has a parent, but the function
     810             :  * cannot find the child in the f_children vector of the parent.
     811             :  * (This should never occur because the set_parent() makes sure
     812             :  * to always keep this relationship proper.)
     813             :  *
     814             :  * \return The offset (index, position) of the child in its parent
     815             :  *         f_children vector.
     816             :  *
     817             :  * \sa set_parent()
     818             :  * \sa replace_with()
     819             :  */
     820       20087 : size_t Node::get_offset() const
     821             : {
     822       20087 :     Node::pointer_t p(f_parent.lock());
     823       20087 :     if(!p)
     824             :     {
     825             :         // no parent
     826           1 :         throw exception_no_parent("get_offset() only works against nodes that have a parent.");
     827             :     }
     828             : 
     829       40172 :     pointer_t me(const_cast<Node *>(this)->shared_from_this());
     830       20086 :     vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
     831       20086 :     if(it == p->f_children.end())
     832             :     {
     833             :         // if this happen, we have a bug in the set_parent() function
     834             :         throw exception_internal_error("get_offset() could not find this node in its parent"); // LCOV_EXCL_LINE
     835             :     }
     836             : 
     837             :     // found ourselves in our parent
     838       40173 :     return it - p->f_children.begin();
     839             : }
     840             : 
     841             : 
     842             : 
     843          63 : }
     844             : // namespace as2js
     845             : 
     846             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10