Inferno  0.2
validate.cpp
Go to the documentation of this file.
00001 /*
00002  * validate.cpp
00003  *
00004  *  Created on: 30 Dec 2009
00005  *      Author: jgraley
00006  */
00007 
00008 #include "validate.hpp"
00009 #include "typeof.hpp"
00010 #include "misc.hpp"
00011 #include "cpptree.hpp"
00012 
00013 using namespace CPPTree;
00014 
00015 void Validate::operator()( TreePtr<Node> context,
00016                TreePtr<Node> *proot )
00017 {
00018   (void)context;
00019   decl_refs.clear();
00020   total_refs.clear();
00021 
00022   // Is the proot reachable from context? If not that's probably because we haven't inserted
00023   // the subtree at proot into the program tree at context yet.
00024   bool connected = false;
00025 
00026   // First walk over the entire context counting incoming links (because
00027   // incoming links from other than the subtree of interest still count
00028   // when validating link counts).
00029   Walk wcon( context );
00030   FOREACH( const TreePtr<Node> x, wcon )
00031   {
00032     if( x )
00033     {
00034       // TODO use UniqueWalk for this!
00035       vector< Itemiser::Element * > members = x->Itemise();
00036         FOREACH( Itemiser::Element *m, members )
00037       {
00038         if( ContainerInterface *con = dynamic_cast<ContainerInterface *>(m) )
00039         {
00040           FOREACH( const TreePtrInterface &tpi, *con )
00041             OnLink( x, tpi );
00042         }
00043         else if( TreePtrInterface *ptr = dynamic_cast<TreePtrInterface *>(m) )
00044         {
00045           OnLink( x, *ptr );
00046         }
00047       }
00048       if( x == *proot )
00049         connected = true;
00050     }
00051   }
00052 
00053   // Now do the actual validation, only on the specified subtree
00054   Walk w( *proot );
00055   for( Walk::iterator wit = w.begin(); wit != w.end(); ++wit )
00056   {
00057     const TreePtr<Node> x = *wit;
00058     if( !is_pattern ) // Don't do these checks on search/replace patterns
00059     {
00060       // NULL pointers not allowed in program tree (though they are allowed in search/replace patterns)
00061       ASSERT( x )("Found NULL pointer in tree at ")( wit );
00062 
00063       // Intermediate nodes are only allowed in search and replace patterns; the trees for programs
00064       // must be built from final nodes.
00065             TRACE("validating finality of ")(*x)(" as %d\n", (int)x->IsFinal() );
00066       ASSERT( x->IsFinal() )( "Found intermediate (non-final) node ")(*x)(" at ")(wit);
00067 
00068       // Check that we can successfully call TypeOf on every Expression
00069       if( TreePtr<Expression> e = dynamic_pointer_cast<Expression>(x) )
00070           (void)TypeOf::instance(context, e);
00071 
00072       // Check that every identifier has a declaration
00073       if( TreePtr<InstanceIdentifier> ii = dynamic_pointer_cast<InstanceIdentifier>(x) )
00074           (void)GetDeclaration()(context, ii);
00075 
00076       // if x is missing it's NODE_FUNCTIONS macro, then the Clone we get (y) will be a clone
00077       // of the most specialised base of x that does have NODE_FUNCTIONS.
00078       TreePtr<Node> y = dynamic_pointer_cast<Node>((*x).Clone());
00079       ASSERT( typeid(*y)==typeid(*x) )(*x)(" apparently does not contain NODE_FUNCTIONS macro because it Clone()s to ")(*y)(" at ")(wit);
00080         }
00081 
00082     if( x && x != context && connected ) // Skip the root, since we won't have counted any refs to it
00083                                        // Also, these rules may be broken for disconnected subtrees
00084     {
00085       TRACE("%p decl_refs=%d total refs=%d\n", x.get(), decl_refs[x], total_refs[x] );
00086       // Check incoming pointers rule: Non-identifier nodes should be referenced exactly once
00087       // Identifiers should be referenced exactly once by the node that declares them,
00088       // and may be referenced zero or more times by other nodes. We skip the
00089       // identifier checks for patterns though (TODO decide what the rule becomes in this case)
00090 /*      if( dynamic_pointer_cast<Identifier>(x) )
00091       {
00092         if( !is_pattern && connected )
00093           ASSERT( decl_refs[x] == 1 )("Identifier ")(*x)(" found with %d declaration references", decl_refs[x])(" at ")(wit)
00094                 ("\nThere must be exactly 1 declaration and zero or more usages");
00095       }
00096       else
00097         ASSERT( total_refs[x] == 1 )("Node ")(*x)(" found with %d references", total_refs[x] )(" at ")(wit)
00098             ("\nThere must be exactly 1 reference to nodes (except identifiers)");*/
00099     }
00100   }
00101 }
00102 
00103 void Validate::OnLink( TreePtr<Node> p, TreePtr<Node> c )
00104 {
00105   TRACE("Ref %p to %p\n", p.get(), c.get() );
00106   if( TreePtr<Instance> pi = dynamic_pointer_cast<Instance>(p) )
00107   {
00108     if( c == pi->identifier )
00109         decl_refs[c]++;
00110   }
00111   else if( TreePtr<UserType> pu = dynamic_pointer_cast<UserType>(p) )
00112   {
00113     if( c == pu->identifier )
00114         decl_refs[c]++;
00115   }
00116   else if( TreePtr<Label> pl = dynamic_pointer_cast<Label>(p) )
00117   {
00118     if( c == pl->identifier )
00119         decl_refs[c]++;
00120   }
00121 
00122   total_refs[c]++;
00123 }
00124 
00125