as2js: /home/snapwebsites/snapcpp/contrib/as2js/lib/node_tree.cpp Source File

as2js  0.1.14
AlexScript to JavaScript
node_tree.cpp
Go to the documentation of this file.
1 /* lib/node_tree.cpp
2 
3 Copyright (c) 2005-2019 Made to Order Software Corp. All Rights Reserved
4 
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 #include "as2js/node.h"
35 
36 #include "as2js/exceptions.h"
37 
38 #include <algorithm>
39 
40 
67 namespace as2js
68 {
69 
70 
71 
72 /**********************************************************************/
73 /**********************************************************************/
74 /*** NODE TREE ******************************************************/
75 /**********************************************************************/
76 /**********************************************************************/
77 
78 
79 
160 void Node::set_parent(pointer_t parent, int index)
161 {
162  // we are modifying the child and both parents
163  modifying();
164 
165  if(parent)
166  {
167  parent->modifying();
168  }
169 
170  Node::pointer_t p(f_parent.lock());
171  if(parent != p && p)
172  {
173  p->modifying();
174  }
175 
176  // already a child of that parent?
177  // (although in case of an insert, we force the re-parent
178  // to the right location)
179  if(parent == p && index == -1)
180  {
181  return;
182  }
183 
184  // tests to make sure that the parent accepts children
185  // (if we got a parent pointer)
186  if(parent) switch(parent->get_type())
187  {
188  case node_t::NODE_UNKNOWN: // this can be anything so we keep it here
189  case node_t::NODE_ADD:
196  case node_t::NODE_DIVIDE:
198  case node_t::NODE_LESS:
200  case node_t::NODE_MODULO:
202  case node_t::NODE_MEMBER:
204  case node_t::NODE_ARRAY:
206  case node_t::NODE_AS:
227  case node_t::NODE_CALL:
228  case node_t::NODE_CASE:
229  case node_t::NODE_CATCH:
230  case node_t::NODE_CLASS:
234  case node_t::NODE_DELETE:
236  case node_t::NODE_DO:
237  case node_t::NODE_ENSURE:
238  case node_t::NODE_ENUM:
239  case node_t::NODE_EQUAL:
241  case node_t::NODE_EXPORT:
244  case node_t::NODE_FOR:
247  case node_t::NODE_IF:
249  case node_t::NODE_IMPORT:
250  case node_t::NODE_IN:
256  case node_t::NODE_IS:
257  case node_t::NODE_LABEL:
259  case node_t::NODE_LIST:
263  case node_t::NODE_MATCH:
266  case node_t::NODE_NAME:
268  case node_t::NODE_NEW:
273  case node_t::NODE_PARAM:
278  case node_t::NODE_POWER:
280  case node_t::NODE_RANGE:
282  case node_t::NODE_RETURN:
283  case node_t::NODE_ROOT:
286  case node_t::NODE_SCOPE:
287  case node_t::NODE_SET:
294  case node_t::NODE_SUPER:
295  case node_t::NODE_SWITCH:
297  case node_t::NODE_THROW:
298  case node_t::NODE_THROWS:
299  case node_t::NODE_TRY:
300  case node_t::NODE_TYPE:
301  case node_t::NODE_TYPEOF:
302  case node_t::NODE_USE:
303  case node_t::NODE_VAR:
306  case node_t::NODE_WHILE:
307  case node_t::NODE_WITH:
308  case node_t::NODE_YIELD:
309  break;
310 
311  // All those node types are assumed to never support a child
313  case node_t::NODE_AUTO:
315  case node_t::NODE_BREAK:
316  case node_t::NODE_BYTE:
317  case node_t::NODE_CHAR:
321  case node_t::NODE_COLON:
322  case node_t::NODE_COMMA:
323  case node_t::NODE_CONST:
326  case node_t::NODE_DOUBLE:
327  case node_t::NODE_ELSE:
328  case node_t::NODE_EMPTY:
329  case node_t::NODE_EOF:
330  case node_t::NODE_FINAL:
331  case node_t::NODE_FLOAT:
333  case node_t::NODE_INLINE:
334  case node_t::NODE_INT64:
335  case node_t::NODE_FALSE:
337  case node_t::NODE_GOTO:
338  case node_t::NODE_LONG:
339  case node_t::NODE_NATIVE:
340  case node_t::NODE_NULL:
346  case node_t::NODE_PUBLIC:
348  case node_t::NODE_REST:
350  case node_t::NODE_SHORT:
351  case node_t::NODE_STATIC:
352  case node_t::NODE_STRING:
353  case node_t::NODE_THEN:
354  case node_t::NODE_THIS:
356  case node_t::NODE_TRUE:
359  case node_t::NODE_VOID:
361  case node_t::NODE_other: // for completeness
362  case node_t::NODE_max: // for completeness
363  // ERROR: some values are not valid as a type
364  if(parent->get_parent())
365  {
366  std::cerr << *parent->get_parent() << std::endl;
367  }
368  throw exception_incompatible_node_type(std::string("invalid type: \"")
369  + parent->get_type_name() + "\" used as a parent node of child with type: \""
370  + get_type_name() + "\".");
371 
372  }
373 
374  // verify that 'this' can be a child
375  switch(f_type)
376  {
380  case node_t::NODE_COLON:
381  case node_t::NODE_COMMA:
382  case node_t::NODE_ELSE:
383  case node_t::NODE_THEN:
384  case node_t::NODE_EOF:
388  case node_t::NODE_ROOT: // correct?
390  case node_t::NODE_other: // for completeness
391  case node_t::NODE_max: // for completeness
392  throw exception_incompatible_node_type("invalid type used as a child node");
393 
394  default:
395  // all others can be children (i.e. most everything)
396  break;
397 
398  }
399 
400  if(p)
401  {
402  // very similar to the get_offset() call only we want the iterator
403  // in this case, not the index
404  pointer_t me(shared_from_this());
405  vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
406  if(it == p->f_children.end())
407  {
408  throw exception_internal_error("trying to remove a child from a parent which does not know about that child"); // LCOV_EXCL_LINE
409  }
410  p->f_children.erase(it);
411  f_parent.reset();
412  }
413 
414  if(parent)
415  {
416  if(index == -1)
417  {
418  parent->f_children.push_back(shared_from_this());
419  }
420  else
421  {
422  if(static_cast<size_t>(index) > parent->f_children.size())
423  {
424  throw exception_index_out_of_range("trying to insert a node at the wrong position");
425  }
426  parent->f_children.insert(parent->f_children.begin() + index, shared_from_this());
427  }
428  f_parent = parent;
429  }
430 }
431 
432 
447 {
448  return f_parent.lock();
449 }
450 
451 
462 {
463  return f_children.size();
464 }
465 
466 
495 void Node::delete_child(int index)
496 {
497  f_children.at(index)->set_parent();
498 }
499 
500 
525 {
526  if(!child)
527  {
528  throw exception_invalid_data("cannot append a child if its pointer is null");
529  }
530  child->set_parent(shared_from_this());
531 }
532 
533 
560 void Node::insert_child(int index, pointer_t child)
561 {
562  if(!child)
563  {
564  throw exception_invalid_data("cannot insert a child if its pointer is null");
565  }
566  child->set_parent(shared_from_this(), index);
567 }
568 
569 
594 void Node::set_child(int index, pointer_t child)
595 {
596  // to respect the contract, we have to test child here too
597  if(!child)
598  {
599  throw exception_invalid_data("cannot insert a child if its pointer is null");
600  }
601  delete_child(index);
602  insert_child(index, child);
603 }
604 
605 
656 {
657  // to respect the contract, we have to test child here too
658  if(!node)
659  {
660  throw exception_invalid_data("cannot replace with a node if its pointer is null");
661  }
662  pointer_t p(f_parent.lock());
663  if(!p)
664  {
665  throw exception_no_parent("trying to replace a node which has no parent");
666  }
667 
668  // the replace is safe so force an unlock in the parent if necessary
669  // it is safe in the sense that the count will remain the same and
670  // that specific offset will remain in place
671  //
672  // specifically, I know this happens when replacing a reference to a
673  // constant variable with its value in the parent expression, the parent
674  // node is locked in that case
675 
676  int32_t const save_lock(p->f_lock);
677  p->f_lock = 0;
678  try
679  {
680  p->set_child(get_offset(), node);
681  }
682  catch(...)
683  {
684  p->f_lock = save_lock;
685  throw;
686  }
687  p->f_lock = save_lock;
688 }
689 
690 
710 {
711  return f_children.at(index);
712 }
713 
714 
736 {
737  Node::pointer_t child;
738  return find_next_child(child, type);
739 }
740 
741 
767 {
768  size_t const max(f_children.size());
769  for(size_t idx(0); idx < max; ++idx)
770  {
771  // if child is defined, skip up to it first
772  if(child && child == f_children[idx])
773  {
774  child.reset();
775  }
776  else if(f_children[idx]->get_type() == type)
777  {
778  return f_children[idx];
779  }
780  }
781 
782  // not found...
783  return pointer_t();
784 }
785 
786 
805 {
806  size_t idx(f_children.size());
807  while(idx > 0)
808  {
809  --idx;
811  {
812  // a delete is automatically recursive
813  delete_child(idx);
814  }
815  else
816  {
817  f_children[idx]->clean_tree(); // recursive
818  }
819  }
820 }
821 
822 
844 size_t Node::get_offset() const
845 {
846  Node::pointer_t p(f_parent.lock());
847  if(!p)
848  {
849  // no parent
850  throw exception_no_parent("get_offset() only works against nodes that have a parent.");
851  }
852 
853  pointer_t me(const_cast<Node *>(this)->shared_from_this());
854  vector_of_pointers_t::iterator it(std::find(p->f_children.begin(), p->f_children.end(), me));
855  if(it == p->f_children.end())
856  {
857  // if this happen, we have a bug in the set_parent() function
858  throw exception_internal_error("get_offset() could not find this node in its parent"); // LCOV_EXCL_LINE
859  }
860 
861  // found ourselves in our parent
862  return it - p->f_children.begin();
863 }
864 
865 
867 {
868  f_instance = node;
869 }
870 
871 
873 {
874  return f_instance.lock();
875 }
876 
877 
878 }
879 // namespace as2js
880 
881 // vim: ts=4 sw=4 et
void append_child(pointer_t child)
Append a child to &#39;this&#39; node.
Definition: node_tree.cpp:524
pointer_t get_child(int index) const
Retrieve a child.
Definition: node_tree.cpp:709
node_t f_type
Definition: node.h:594
weak_pointer_t f_instance
Definition: node.h:620
void replace_with(pointer_t node)
Replace this node with the node parameter.
Definition: node_tree.cpp:655
void set_parent(pointer_t parent=pointer_t(), int index=-1)
This function sets the parent of a node.
Definition: node_tree.cpp:160
void modifying() const
Test whether the node can be modified.
Definition: node_lock.cpp:91
vector_of_pointers_t f_children
Definition: node.h:619
std::shared_ptr< Node > pointer_t
Definition: node.h:67
size_t get_children_size() const
Return the number of children available in this node.
Definition: node_tree.cpp:461
weak_pointer_t f_parent
Definition: node.h:617
void delete_child(int index)
Delete the specified child from the parent.
Definition: node_tree.cpp:495
pointer_t get_parent() const
Get a pointer to the parent of this node.
Definition: node_tree.cpp:446
void insert_child(int index, pointer_t child)
Insert the specified child at the specified location.
Definition: node_tree.cpp:560
pointer_t get_instance() const
Definition: node_tree.cpp:872
The AlexScript to JavaScript namespace.
Definition: compiler.cpp:37
void set_instance(pointer_t node)
Definition: node_tree.cpp:866
void set_child(int index, pointer_t child)
Replace the current child at position index with child.
Definition: node_tree.cpp:594
node_t get_type() const
Retrieve the type of the node.
Definition: node_type.cpp:367
size_t get_offset() const
Find the offset of this node in its parent array of children.
Definition: node_tree.cpp:844
pointer_t find_first_child(node_t type) const
Find the first child of a given type.
Definition: node_tree.cpp:735
pointer_t find_next_child(pointer_t start, node_t type) const
Find the next child with the specified type.
Definition: node_tree.cpp:766
void clean_tree()
Remove all the unknown nodes.
Definition: node_tree.cpp:804
char const * get_type_name() const
Retrieve the type of this node.
Definition: node_type.cpp:475

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.

Syndicate content

Snap! Websites
An Open Source CMS System in C++

Contact Us Directly