LCOV - code coverage report
Current view: top level - as2js/lib - node_tree.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 84 84 100.0 %
Date: 2014-08-10 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             : namespace as2js
      44             : {
      45             : 
      46             : 
      47             : 
      48             : /**********************************************************************/
      49             : /**********************************************************************/
      50             : /***  NODE TREE  ******************************************************/
      51             : /**********************************************************************/
      52             : /**********************************************************************/
      53             : 
      54             : 
      55             : 
      56             : /** \brief This function sets the parent of a node.
      57             :  *
      58             :  * This function is the only function that handles the tree of nodes,
      59             :  * in other words, the only one that modifies the f_parent and
      60             :  * f_children pointers. It is done that way to make 100% sure (assuming
      61             :  * it is itself correct) that we do not mess up the tree.
      62             :  *
      63             :  * This node loses its current parent, and thus is removed from the
      64             :  * list of children of that parent. Then is is assigned the new
      65             :  * parent as passed to this function.
      66             :  *
      67             :  * If an index is specified, the child is inserted at that specific
      68             :  * location. Otherwise the child is appended.
      69             :  *
      70             :  * The function does nothing if the current parent is the same as the
      71             :  * new parent and the default index is used (-1).
      72             :  *
      73             :  * Use an index of 0 to insert the item at the start of the list of children.
      74             :  * Use an index of get_children_size() to force the child at the end of the
      75             :  * list even if the parent remains the same.
      76             :  *
      77             :  * Helper functions are available to make more sense of the usage of this
      78             :  * function but they all are based on the set_parent() function:
      79             :  *
      80             :  * \li delete_child() -- delete a child at that specific index.
      81             :  * \li append_child() -- append a child to this parent.
      82             :  * \li insert_child() -- insert a child to this parent.
      83             :  * \li set_child() -- replace a child with another in this parent.
      84             :  * \li replace_with() -- replace a child with another not knowing its offset.
      85             :  *
      86             :  * \param[in] parent  The new parent of the node. May be set to nullptr.
      87             :  * \param[in] index  The position where the new item is inserted in the parent
      88             :  *                   array of children. If -1, append at the end of the list.
      89             :  */
      90    21404153 : void Node::set_parent(pointer_t parent, int index)
      91             : {
      92             :     // we are modifying the child and both parents
      93    21404153 :     modifying();
      94             : 
      95    21404152 :     if(parent)
      96             :     {
      97    20511110 :         parent->modifying();
      98             :     }
      99             : 
     100    21404152 :     Node::pointer_t p(f_parent.lock());
     101    21404152 :     if(parent != p && p)
     102             :     {
     103      893044 :         p->modifying();
     104             :     }
     105             : 
     106             :     // already a child of that parent?
     107             :     // (although in case of an insert, we force the re-parent
     108             :     // to the right location)
     109    21404152 :     if(parent == p && index == -1)
     110             :     {
     111    21394466 :         return;
     112             :     }
     113             : 
     114             :     // tests to make sure that the parent accepts children
     115             :     // (if we got a parent pointer)
     116    21404152 :     if(parent) switch(parent->get_type())
     117             :     {
     118             :     case node_t::NODE_UNKNOWN: // this can be anything so we keep it here
     119             :     case node_t::NODE_ADD:
     120             :     case node_t::NODE_BITWISE_AND:
     121             :     case node_t::NODE_BITWISE_NOT:
     122             :     case node_t::NODE_ASSIGNMENT:
     123             :     case node_t::NODE_BITWISE_OR:
     124             :     case node_t::NODE_BITWISE_XOR:
     125             :     case node_t::NODE_CONDITIONAL:
     126             :     case node_t::NODE_DIVIDE:
     127             :     case node_t::NODE_GREATER:
     128             :     case node_t::NODE_LESS:
     129             :     case node_t::NODE_LOGICAL_NOT:
     130             :     case node_t::NODE_MODULO:
     131             :     case node_t::NODE_MULTIPLY:
     132             :     case node_t::NODE_MEMBER:
     133             :     case node_t::NODE_SUBTRACT:
     134             :     case node_t::NODE_ARRAY:
     135             :     case node_t::NODE_ARRAY_LITERAL:
     136             :     case node_t::NODE_AS:
     137             :     case node_t::NODE_ASSIGNMENT_ADD:
     138             :     case node_t::NODE_ASSIGNMENT_BITWISE_AND:
     139             :     case node_t::NODE_ASSIGNMENT_BITWISE_OR:
     140             :     case node_t::NODE_ASSIGNMENT_BITWISE_XOR:
     141             :     case node_t::NODE_ASSIGNMENT_DIVIDE:
     142             :     case node_t::NODE_ASSIGNMENT_LOGICAL_AND:
     143             :     case node_t::NODE_ASSIGNMENT_LOGICAL_OR:
     144             :     case node_t::NODE_ASSIGNMENT_LOGICAL_XOR:
     145             :     case node_t::NODE_ASSIGNMENT_MAXIMUM:
     146             :     case node_t::NODE_ASSIGNMENT_MINIMUM:
     147             :     case node_t::NODE_ASSIGNMENT_MODULO:
     148             :     case node_t::NODE_ASSIGNMENT_MULTIPLY:
     149             :     case node_t::NODE_ASSIGNMENT_POWER:
     150             :     case node_t::NODE_ASSIGNMENT_ROTATE_LEFT:
     151             :     case node_t::NODE_ASSIGNMENT_ROTATE_RIGHT:
     152             :     case node_t::NODE_ASSIGNMENT_SHIFT_LEFT:
     153             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT:
     154             :     case node_t::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
     155             :     case node_t::NODE_ASSIGNMENT_SUBTRACT:
     156             :     case node_t::NODE_ATTRIBUTES:
     157             :     case node_t::NODE_CALL:
     158             :     case node_t::NODE_CASE:
     159             :     case node_t::NODE_CATCH:
     160             :     case node_t::NODE_CLASS:
     161             :     case node_t::NODE_COMPARE:
     162             :     case node_t::NODE_DEBUGGER:
     163             :     case node_t::NODE_DECREMENT:
     164             :     case node_t::NODE_DELETE:
     165             :     case node_t::NODE_DIRECTIVE_LIST:
     166             :     case node_t::NODE_DO:
     167             :     case node_t::NODE_ENSURE:
     168             :     case node_t::NODE_ENUM:
     169             :     case node_t::NODE_EQUAL:
     170             :     case node_t::NODE_EXCLUDE:
     171             :     case node_t::NODE_EXPORT:
     172             :     case node_t::NODE_EXTENDS:
     173             :     case node_t::NODE_FINALLY:
     174             :     case node_t::NODE_FOR:
     175             :     case node_t::NODE_FUNCTION:
     176             :     case node_t::NODE_GREATER_EQUAL:
     177             :     case node_t::NODE_IF:
     178             :     case node_t::NODE_IMPLEMENTS:
     179             :     case node_t::NODE_IMPORT:
     180             :     case node_t::NODE_IN:
     181             :     case node_t::NODE_INCLUDE:
     182             :     case node_t::NODE_INCREMENT:
     183             :     case node_t::NODE_INSTANCEOF:
     184             :     case node_t::NODE_INTERFACE:
     185             :     case node_t::NODE_INVARIANT:
     186             :     case node_t::NODE_IS:
     187             :     case node_t::NODE_LABEL:
     188             :     case node_t::NODE_LESS_EQUAL:
     189             :     case node_t::NODE_LIST:
     190             :     case node_t::NODE_LOGICAL_AND:
     191             :     case node_t::NODE_LOGICAL_OR:
     192             :     case node_t::NODE_LOGICAL_XOR:
     193             :     case node_t::NODE_MATCH:
     194             :     case node_t::NODE_MAXIMUM:
     195             :     case node_t::NODE_MINIMUM:
     196             :     case node_t::NODE_NAME:
     197             :     case node_t::NODE_NAMESPACE:
     198             :     case node_t::NODE_NEW:
     199             :     case node_t::NODE_NOT_EQUAL:
     200             :     case node_t::NODE_NOT_MATCH:
     201             :     case node_t::NODE_OBJECT_LITERAL:
     202             :     case node_t::NODE_PACKAGE:
     203             :     case node_t::NODE_PARAM:
     204             :     case node_t::NODE_PARAMETERS:
     205             :     case node_t::NODE_PARAM_MATCH:
     206             :     case node_t::NODE_POST_DECREMENT:
     207             :     case node_t::NODE_POST_INCREMENT:
     208             :     case node_t::NODE_POWER:
     209             :     case node_t::NODE_PROGRAM:
     210             :     case node_t::NODE_RANGE:
     211             :     case node_t::NODE_REQUIRE:
     212             :     case node_t::NODE_RETURN:
     213             :     case node_t::NODE_ROOT:
     214             :     case node_t::NODE_ROTATE_LEFT:
     215             :     case node_t::NODE_ROTATE_RIGHT:
     216             :     case node_t::NODE_SCOPE:
     217             :     case node_t::NODE_SET:
     218             :     case node_t::NODE_SHIFT_LEFT:
     219             :     case node_t::NODE_SHIFT_RIGHT:
     220             :     case node_t::NODE_SHIFT_RIGHT_UNSIGNED:
     221             :     case node_t::NODE_SMART_MATCH:
     222             :     case node_t::NODE_STRICTLY_EQUAL:
     223             :     case node_t::NODE_STRICTLY_NOT_EQUAL:
     224             :     case node_t::NODE_SUPER:
     225             :     case node_t::NODE_SWITCH:
     226             :     case node_t::NODE_SYNCHRONIZED:
     227             :     case node_t::NODE_THROW:
     228             :     case node_t::NODE_THROWS:
     229             :     case node_t::NODE_TRY:
     230             :     case node_t::NODE_TYPE:
     231             :     case node_t::NODE_TYPEOF:
     232             :     case node_t::NODE_USE:
     233             :     case node_t::NODE_VAR:
     234             :     case node_t::NODE_VARIABLE:
     235             :     case node_t::NODE_VAR_ATTRIBUTES:
     236             :     case node_t::NODE_WHILE:
     237             :     case node_t::NODE_WITH:
     238             :     case node_t::NODE_YIELD:
     239    20502998 :         break;
     240             : 
     241             :     // All those node types are assumed to never support a child
     242             :     case node_t::NODE_ABSTRACT:
     243             :     case node_t::NODE_AUTO:
     244             :     case node_t::NODE_BOOLEAN:
     245             :     case node_t::NODE_BREAK:
     246             :     case node_t::NODE_BYTE:
     247             :     case node_t::NODE_CHAR:
     248             :     case node_t::NODE_CLOSE_CURVLY_BRACKET:
     249             :     case node_t::NODE_CLOSE_PARENTHESIS:
     250             :     case node_t::NODE_CLOSE_SQUARE_BRACKET:
     251             :     case node_t::NODE_COLON:
     252             :     case node_t::NODE_COMMA:
     253             :     case node_t::NODE_CONST:
     254             :     case node_t::NODE_CONTINUE:
     255             :     case node_t::NODE_DEFAULT:
     256             :     case node_t::NODE_DOUBLE:
     257             :     case node_t::NODE_ELSE:
     258             :     case node_t::NODE_EMPTY:
     259             :     case node_t::NODE_EOF:
     260             :     case node_t::NODE_FINAL:
     261             :     case node_t::NODE_FLOAT:
     262             :     case node_t::NODE_IDENTIFIER:
     263             :     case node_t::NODE_INT64:
     264             :     case node_t::NODE_FALSE:
     265             :     case node_t::NODE_FLOAT64:
     266             :     case node_t::NODE_GOTO:
     267             :     case node_t::NODE_LONG:
     268             :     case node_t::NODE_NATIVE:
     269             :     case node_t::NODE_NULL:
     270             :     case node_t::NODE_OPEN_CURVLY_BRACKET:
     271             :     case node_t::NODE_OPEN_PARENTHESIS:
     272             :     case node_t::NODE_OPEN_SQUARE_BRACKET:
     273             :     case node_t::NODE_PRIVATE:
     274             :     case node_t::NODE_PROTECTED:
     275             :     case node_t::NODE_PUBLIC:
     276             :     case node_t::NODE_REGULAR_EXPRESSION:
     277             :     case node_t::NODE_REST:
     278             :     case node_t::NODE_SEMICOLON:
     279             :     case node_t::NODE_SHORT:
     280             :     case node_t::NODE_STATIC:
     281             :     case node_t::NODE_STRING:
     282             :     case node_t::NODE_THEN:
     283             :     case node_t::NODE_THIS:
     284             :     case node_t::NODE_TRANSIENT:
     285             :     case node_t::NODE_TRUE:
     286             :     case node_t::NODE_UNDEFINED:
     287             :     case node_t::NODE_VIDENTIFIER:
     288             :     case node_t::NODE_VOID:
     289             :     case node_t::NODE_VOLATILE:
     290             :     case node_t::NODE_other:        // for completeness
     291             :     case node_t::NODE_max:          // for completeness
     292             :         // ERROR: some values are not valid as a type
     293    20511110 :         throw exception_incompatible_node_type("invalid type used as a parent node");
     294             : 
     295             :     }
     296             : 
     297             :     // verify that 'this' can be a child
     298    21396040 :     switch(f_type)
     299             :     {
     300             :     case node_t::NODE_CLOSE_CURVLY_BRACKET:
     301             :     case node_t::NODE_CLOSE_PARENTHESIS:
     302             :     case node_t::NODE_CLOSE_SQUARE_BRACKET:
     303             :     case node_t::NODE_COLON:
     304             :     case node_t::NODE_COMMA:
     305             :     case node_t::NODE_ELSE:
     306             :     case node_t::NODE_THEN:
     307             :     case node_t::NODE_EOF:
     308             :     case node_t::NODE_OPEN_CURVLY_BRACKET:
     309             :     case node_t::NODE_OPEN_PARENTHESIS:
     310             :     case node_t::NODE_OPEN_SQUARE_BRACKET:
     311             :     case node_t::NODE_ROOT: // correct?
     312             :     case node_t::NODE_SEMICOLON:
     313             :     case node_t::NODE_other:        // for completeness
     314             :     case node_t::NODE_max:          // for completeness
     315        1573 :         throw exception_incompatible_node_type("invalid type used as a child node");
     316             : 
     317             :     default:
     318             :         // all others can be children (i.e. most everything)
     319    21394467 :         break;
     320             : 
     321             :     }
     322             : 
     323    21394467 :     if(p)
     324             :     {
     325             :         // very similar to the get_offset() call only we want the iterator
     326             :         // in this case, not the index
     327      893044 :         pointer_t me(shared_from_this());
     328      893044 :         vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
     329      893044 :         if(it == p->f_children.end())
     330             :         {
     331             :             throw exception_internal_error("trying to remove a child from a parent which does not know about that child"); // LCOV_EXCL_LINE
     332             :         }
     333      893044 :         p->f_children.erase(it);
     334      893044 :         f_parent.reset();
     335             :     }
     336             : 
     337    21394467 :     if(parent)
     338             :     {
     339    20501425 :         if(index == -1)
     340             :         {
     341    20501416 :             parent->f_children.push_back(shared_from_this());
     342             :         }
     343             :         else
     344             :         {
     345           9 :             if(static_cast<size_t>(index) > parent->f_children.size())
     346             :             {
     347           1 :                 throw exception_index_out_of_range("trying to insert a node at the wrong position");
     348             :             }
     349           8 :             parent->f_children.insert(parent->f_children.begin() + index, shared_from_this());
     350             :         }
     351    21394466 :         f_parent = parent;
     352    21404152 :     }
     353             : }
     354             : 
     355             : 
     356             : /** \brief Get a pointer to the parent of this node.
     357             :  *
     358             :  * This function returns the pointer to the parent of this node. It may be
     359             :  * a null pointer.
     360             :  *
     361             :  * Note that the parent is kept as a weak pointer internally. However, when
     362             :  * returned it gets locked first so you do not have to do that yourselves.
     363             :  *
     364             :  * \return A smart pointer to the parent node, may be null.
     365             :  */
     366      719869 : Node::pointer_t Node::get_parent() const
     367             : {
     368      719869 :     return f_parent.lock();
     369             : }
     370             : 
     371             : 
     372             : /** \brief Return the number of children available in this node.
     373             :  *
     374             :  * This function returns the number of children we have available in this
     375             :  * node.
     376             :  *
     377             :  * \return The number of children, may be zero.
     378             :  */
     379    29136624 : size_t Node::get_children_size() const
     380             : {
     381    29136624 :     return f_children.size();
     382             : }
     383             : 
     384             : 
     385             : /** \brief Delete the specified child from the parent.
     386             :  *
     387             :  * This function removes a child from its parent (i.e. "unparent" a
     388             :  * node.)
     389             :  *
     390             :  * The following two lines of code are identical:
     391             :  *
     392             :  * \code
     393             :  *     parent->delete_child(index);
     394             :  *     // or
     395             :  *     parent->set_parent(nullptr, index);
     396             :  * \endcode
     397             :  *
     398             :  * Note that the vector of children of 'this' node changes, be careful.
     399             :  *
     400             :  * \note
     401             :  * The child node being "deleted" is not actively deleted. That is, if
     402             :  * anyone still holds a shared pointer of that node, it will not actually
     403             :  * get deleted. If that was the last shred holding that node, then
     404             :  * it gets deleted automatically by the smart pointer implementation.
     405             :  *
     406             :  * \param[in] index  The index of the child node to remove from 'this' node.
     407             :  */
     408      893043 : void Node::delete_child(int index)
     409             : {
     410      893043 :     f_children.at(index)->set_parent();
     411      893042 : }
     412             : 
     413             : 
     414             : /** \brief Append a child to 'this' node.
     415             :  *
     416             :  * This function appends (adds at the end of the vector of children) a
     417             :  * child to 'this' node, which means the child is given 'this' node as
     418             :  * a parent.
     419             :  *
     420             :  * The following two lines of code are identical:
     421             :  *
     422             :  * \code
     423             :  *     parent->append_child(child);
     424             :  *     // or
     425             :  *     child->set_parent(parent);
     426             :  * \endcode
     427             :  *
     428             :  * \param[in] child  The child to be added at the end of 'this' vector
     429             :  *                   of children.
     430             :  */
     431    20496930 : void Node::append_child(pointer_t child)
     432             : {
     433    20496930 :     if(!child)
     434             :     {
     435           1 :         throw exception_invalid_data("cannot append a child if its pointer is null");
     436             :     }
     437    20496929 :     child->set_parent(shared_from_this());
     438    20492065 : }
     439             : 
     440             : 
     441             : /** \brief Insert the specified child at the specified location.
     442             :  *
     443             :  * When adding a child to a node, it can be placed before existing
     444             :  * children of that node. This function is used for this purpose.
     445             :  *
     446             :  * By default the index is set to -1 which means that the child is
     447             :  * added at the end of the list (see also the append_child() function.)
     448             :  *
     449             :  * This is a helper function since you could as well call the set_parent()
     450             :  * function directly:
     451             :  *
     452             :  * \code
     453             :  *     parent->insert_child(index, child);
     454             :  *     // or
     455             :  *     child->set_parent(parent, index);
     456             :  * \endcode
     457             :  *
     458             :  * \param[in] index  The index where the child will be inserted.
     459             :  * \param[in,out] child  The child to insert at that index.
     460             :  */
     461          11 : void Node::insert_child(int index, pointer_t child)
     462             : {
     463          11 :     child->set_parent(shared_from_this(), index);
     464          10 : }
     465             : 
     466             : 
     467             : /** \brief Replace the current child at position \p index with \p child.
     468             :  *
     469             :  * This function replaces the child in this node at \p index with
     470             :  * the new specified \p child.
     471             :  *
     472             :  * This is a helper function as this functionality is offered by
     473             :  * the set_parent() function as in:
     474             :  *
     475             :  * \code
     476             :  *     parent->set_child(index, child);
     477             :  *     // or
     478             :  *     parent->set_parent(nullptr, index);
     479             :  *     child->set_parent(index, parent);
     480             :  * \endcode
     481             :  *
     482             :  * \param[in] index  The position where the new child is to be placed.
     483             :  * \param[in,out] child  The new child replacing the existing child at \p index.
     484             :  */
     485           3 : void Node::set_child(int index, pointer_t child)
     486             : {
     487           3 :     delete_child(index);
     488           3 :     insert_child(index, child);
     489           3 : }
     490             : 
     491             : 
     492             : /** \brief Replace this node with the \p node parameter.
     493             :  *
     494             :  * This function replaces this node with the specified node. This is used
     495             :  * a lot in the optimizer and once in the compiler.
     496             :  *
     497             :  * It is useful in a case such as an if() statement that has a resulting
     498             :  * Boolean value which is known at compile time. For example:
     499             :  *
     500             :  * \code
     501             :  *  if(true)
     502             :  *      blah;
     503             :  *  else
     504             :  *      foo;
     505             :  * \endcode
     506             :  *
     507             :  * can be optimized by just this:
     508             :  *
     509             :  * \code
     510             :  *  blah;
     511             :  * \endcode
     512             :  *
     513             :  * In that case what we do is replace the NODE_IF (this) with the content
     514             :  * of the 'blah' node.
     515             :  *
     516             :  * This function is very similar to the set_child() when you do not know
     517             :  * the index position of 'this' node in its parent or do not have the
     518             :  * parent node handy. This is the equivalent code for this helper
     519             :  * function:
     520             :  *
     521             :  * \code
     522             :  *     child->replace_with(node);
     523             :  *     // or
     524             :  *     int index(child->get_offset());
     525             :  *     Node::pointer_t parent(child->get_parent());
     526             :  *     parent->set_parent(nullptr, index);
     527             :  *     child->set_parent(index, parent);
     528             :  * \endcode
     529             :  *
     530             :  * \warning
     531             :  * This function modifies the tree in a way that may break loops over
     532             :  * node children.
     533             :  *
     534             :  * \exception exception_internal_error
     535             :  * If 'this' node does not have a parent node, then this exception is
     536             :  * raised.
     537             :  *
     538             :  * \param[in] node  The node to replace 'this' node with.
     539             :  */
     540           2 : void Node::replace_with(pointer_t node)
     541             : {
     542           2 :     pointer_t p(f_parent.lock());
     543           2 :     if(!p)
     544             :     {
     545           1 :         throw exception_no_parent("trying to replace a node which has no parent");
     546             :     }
     547           2 :     p->set_child(get_offset(), node);
     548           1 : }
     549             : 
     550             : 
     551             : /** \brief Retrieve a child.
     552             :  *
     553             :  * This function retrieves a child from this parent node.
     554             :  *
     555             :  * Note that if the index is too large, the function will throw an error.
     556             :  *
     557             :  * \param[in] index  The index of the child to retrieve.
     558             :  *
     559             :  * \return A shared pointer to the specified child.
     560             :  */
     561    20550837 : Node::pointer_t Node::get_child(int index) const
     562             : {
     563    20550837 :     return f_children.at(index);
     564             : }
     565             : 
     566             : 
     567             : /** \brief Find the first child of a given type.
     568             :  *
     569             :  * This function searches the vector of children for the next child
     570             :  * with the specified \p type. This can be used to quickly scan a
     571             :  * list of children for the first node with a specific type.
     572             :  *
     573             :  * \node
     574             :  * This function calls the find_next_child() with a null pointer in
     575             :  * the child parameter.
     576             :  *
     577             :  * \param[in] type  The type of nodes you are interested in.
     578             :  *
     579             :  * \return A pointer to the first node of that type or a null pointer.
     580             :  */
     581       18876 : Node::pointer_t Node::find_first_child(node_t type) const
     582             : {
     583       18876 :     Node::pointer_t child;
     584       18876 :     return find_next_child(child, type);
     585             : }
     586             : 
     587             : 
     588             : /** \brief Find the next child with the specified type.
     589             :  *
     590             :  * This function searches the vector of children for the next child
     591             :  * with the specified \p type. This can be used to quickly scan a
     592             :  * list of children for a specific type of node.
     593             :  *
     594             :  * The \p child parameter can be set to nullptr in which case the
     595             :  * first child of that type is returned (like find_first_child()
     596             :  * would do for you.)
     597             :  *
     598             :  * \note
     599             :  * If you have to manage all the nodes of a given type in a large
     600             :  * list, it is wise to create your own loop because this loop
     601             :  * restarts from index zero every single time.
     602             :  *
     603             :  * \param[in] child  A pointer to the previously returned child node.
     604             :  * \param[in] type  The type of children to look for.
     605             :  *
     606             :  * \return The next child of that type or a null pointer.
     607             :  */
     608       37752 : Node::pointer_t Node::find_next_child(pointer_t child, node_t type) const
     609             : {
     610       37752 :     size_t const max(f_children.size());
     611     2982408 :     for(size_t idx(0); idx < max; ++idx)
     612             :     {
     613             :         // if child is defined, skip up to it first
     614     2963532 :         if(child && child == f_children[idx])
     615             :         {
     616       18876 :             child.reset();
     617             :         }
     618     2944656 :         else if(f_children[idx]->get_type() == type)
     619             :         {
     620       18876 :             return f_children[idx];
     621             :         }
     622             :     }
     623             : 
     624             :     // not found...
     625       18876 :     return pointer_t();
     626             : }
     627             : 
     628             : 
     629             : /** \brief Remove all the unknown nodes.
     630             :  *
     631             :  * This function goes through the entire tree starting at 'this' node
     632             :  * and remove all the children that are marked as NODE_UNKNOWN.
     633             :  *
     634             :  * This allows many functions to clear out many nodes without
     635             :  * having to have very special handling of their loops while
     636             :  * scanning all the children of a node.
     637             :  *
     638             :  * \note
     639             :  * The nodes themselves do not get deleted by this function. If
     640             :  * it was their last reference then it will be deleted by the
     641             :  * shared pointer code as expected.
     642             :  */
     643          12 : void Node::clean_tree()
     644             : {
     645          12 :     size_t idx(f_children.size());
     646          20 :     while(idx > 0)
     647             :     {
     648          12 :         --idx;
     649          12 :         if(f_children[idx]->get_type() == node_t::NODE_UNKNOWN)
     650             :         {
     651           2 :             delete_child(idx);
     652             :         }
     653             :         else
     654             :         {
     655          10 :             f_children[idx]->clean_tree();  // recursive
     656             :         }
     657             :     }
     658           8 : }
     659             : 
     660             : 
     661             : /** \brief Find the offset of this node in its parent array of children.
     662             :  *
     663             :  * This function searches for a node in its parent list of children and
     664             :  * returns the corresponding index so we can apply functions to that
     665             :  * child from the parent.
     666             :  *
     667             :  * \exception exception_no_parent
     668             :  * This exception is raised if the object does not have a parent.
     669             :  *
     670             :  * \exception exception_internal_error
     671             :  * This exception is raised if the node has a parent, but the function
     672             :  * cannot find the child in the f_children vector of the parent.
     673             :  * (This should never occur because the set_parent() makes sure
     674             :  * to always keep this relationship proper.)
     675             :  *
     676             :  * \return The offset (index, position) of the child in its parent
     677             :  *         f_children vector.
     678             :  */
     679       18878 : size_t Node::get_offset() const
     680             : {
     681       18878 :     Node::pointer_t p(f_parent.lock());
     682       18878 :     if(!p)
     683             :     {
     684             :         // no parent
     685           1 :         throw exception_no_parent("get_offset() only works against nodes that have a parent.");
     686             :     }
     687             : 
     688       37754 :     pointer_t me = const_cast<Node *>(this)->shared_from_this();
     689       18877 :     vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
     690       18877 :     if(it == p->f_children.end())
     691             :     {
     692             :         // if this happen, we have a bug in the set_parent() function
     693             :         throw exception_internal_error("get_offset() could not find this node in its parent"); // LCOV_EXCL_LINE
     694             :     }
     695             : 
     696             :     // found ourselves in our parent
     697       37755 :     return it - p->f_children.begin();
     698             : }
     699             : 
     700             : 
     701             : 
     702          20 : }
     703             : // namespace as2js
     704             : 
     705             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.9