void HlModel::SetSortOrders( SgNode *pNode, BtU32 sortOrder ) { if( pNode->HasMaterials() ) { SgMaterial* pMaterials = pNode->pMaterial(); // Cache the number of materials BtU32 numMaterials = pMaterials->NumMaterials(); for( BtU32 i=0; i<numMaterials; i++) { // Cache the material RsMaterial* pMaterial = pMaterials->GetMaterial( i ); // Set the sort order pMaterial->SetSortOrder( sortOrder ); // Set the material pMaterials->SetMaterial( i, pMaterial ); } } // Cache the first child SgNode* pChild = pNode->pFirstChild(); // Loop through the children while( pChild != BtNull ) { // Set the materials SetSortOrders( pChild, sortOrder ); // Move to the next child pChild = pChild->pNextSibling(); } }
ffi_type *getFFIClassType(SgClassType *ct) { const StructLayoutInfo &sli = typeLayout(ct); ffi_type **fieldTypes = new ffi_type*[sli.fields.size()]; allocatedTypeArrays.push_back(fieldTypes); for (size_t i = 0; i < sli.fields.size(); i++) { SgNode *decl = sli.fields[i].decl; if (SgInitializedName *in = isSgInitializedName(decl)) { fieldTypes[i] = getFFIType(in->get_type()); } else if (SgBaseClass *bc = isSgBaseClass(decl)) { fieldTypes[i] = getFFIType(bc->get_base_class()->get_type()); } else { throw InterpError("Encountered unsupported field decl: " + decl->class_name()); } } ffi_type *ctType = new ffi_type; allocatedTypes.push_back(ctType); ctType->elements = fieldTypes; return ctType; }
/* * Check to see if a variable has its address taken in an I/O operation. */ bool RegisterPointers::isAddrTakenInIrrelevantFunc(SgVarRefExp* expr) { //TODO get function call name /*SgExprStatement* stmt = isSgExprStatement(getEnclosingStatement(expr)); if(!stmt) return false; SgFunctionCallExp* funcCall = isSgFunctionCallExp(stmt->get_expression()); if(!funcCall) return false; string name = NAME(funcCall->getAssociatedFunctionSymbol());*/ SgStatement* encStmt = getEnclosingStatement(expr); SgNode* parent = expr->get_parent(); SgFunctionCallExp* funcCall = NULL; while(parent != encStmt) { funcCall = isSgFunctionCallExp(parent); if(funcCall && (functions.find(NAME(funcCall->getAssociatedFunctionSymbol())) != functions.end())) return true; parent = parent->get_parent(); } /*set<string>::const_iterator funcIt = functions.begin(); for(funcIt = functions.begin(); funcIt != functions.end(); funcIt++) { if(name.find(*funcIt) != string::npos) return true; }*/ return false; }
void SgGameWriter::WriteNode(const SgNode& node, bool allProps, int boardSize, SgPropPointFmt fmt) { for (SgPropListIterator it(node.Props()); it; ++it) { SgProp* prop = *it; vector<string> values; // Check whether property should be written, and get its value. if ((allProps || ShouldWriteProperty(*prop)) && prop->ToString(values, boardSize, fmt, m_fileFormat)) { // Start specific properties on a new line to make file easier // to read. if (prop->Flag(SG_PROPCLASS_NEWLINE)) StartNewLine(); m_out << prop->Label(); for (vector<string>::const_iterator it2 = values.begin(); it2 != values.end(); ++it2) m_out << '[' << (*it2) << ']'; // Limit number of properties per line. if (++m_numPropsOnLine >= 10) StartNewLine(); } } // Start first move node after root node on a new line. if (node.HasProp(SG_PROP_GAME)) StartNewLine(); }
//Returns the next SSA form number for the variable s that is declared or assigned a value in the inTrueBranch branch of the if node labeled with *condLabel //Generates/updates the phi statement for the variable in the node labeled with *condLabel int SSAGenerator::nextNumber(string s, Label* condLabel, bool inTrueBranch) { map<string, int>::iterator i = currentNumberMap.find(s); if(i == currentNumberMap.end()) //Variable has never been declared yet so no current number exists for the variable { currentNumberMap.insert(pair<string, int>(s, 0)); return 0; } else //Variable has been declared before so a current number for the variable exists { i->second = i->second + 1; if(condLabel != NULL) //Condition node exists { SgNode* condNode = labeler->getNode(*condLabel); AstAttribute* condAtt = condNode->getAttribute("PHI"); assert(condAtt != NULL); PhiAttribute* condPhiAtt = dynamic_cast<PhiAttribute*>(condAtt); assert(condPhiAtt != NULL); //Generate/update the phi statement for the variable in the condition node if it is not declared locally in the current branch bool declaredLocally = (inTrueBranch && (condPhiAtt->varsDeclaredInTrueBranch.find(s) != condPhiAtt->varsDeclaredInTrueBranch.end())) || (!inTrueBranch && (condPhiAtt->varsDeclaredInFalseBranch.find(s) != condPhiAtt->varsDeclaredInFalseBranch.end())); if(!declaredLocally) { PhiStatement* phi = condPhiAtt->getPhiFor(s); if(phi == NULL){ phi = condPhiAtt->generatePhiFor(s); } if(inTrueBranch) phi->trueNumber = i->second; else phi->falseNumber = i->second; } } return i->second; } }
bool declarationHasTranslationUnitScope (const SgDeclarationStatement* decl) { ROSE_ASSERT(decl != NULL); SgNode *declParent = decl->get_parent(); ROSE_ASSERT(declParent != NULL); VariantT declParentV = declParent->variantT(); if (declParentV == V_SgGlobal || declParentV == V_SgNamespaceDefinitionStatement) { // If the declaration is static (in the C sense), it will have translation unit scope. if (decl->get_declarationModifier().get_storageModifier().isStatic()) return true; // Likewise if the declaration is an inline function. if (const SgFunctionDeclaration *fnDecl = isSgFunctionDeclaration(decl)) { if (fnDecl->get_functionModifier().isInline()) return true; } } // Likewise if the declaration is an anonymous namespace if (const SgNamespaceDeclarationStatement *nsDecl = isSgNamespaceDeclarationStatement(decl)) { if (nsDecl->get_isUnnamedNamespace()) return true; } return false; }
void SgNode::PathToRoot(SgVectorOf<SgNode>* path) const { path->Clear(); for (SgNode* node = const_cast<SgNode*>(this); node; node = node->Father()) path->PushBack(node); }
void HlModel::SetTextures( SgNode *pNode, BtU32 index, RsTexture *pTexture ) { // Cache the materials SgMaterial* pMaterials = pNode->pMaterial(); // Cache the number of materials BtU32 numMaterials = pMaterials->NumMaterials(); for( BtU32 i=0; i<numMaterials; i++) { // Cache the material RsMaterial* pMaterial = pMaterials->GetMaterial( i ); // Set the texture pMaterial->SetTexture( index, pTexture ); } // Cache the first child SgNode* pChild = pNode->pFirstChild(); // Loop through the children while( pChild != BtNull ) { // Set the materials SetTextures( pChild, index, pTexture ); // Move to the next child pChild = pChild->pNextSibling(); } }
string SgNode::TreeIndex(const SgNode* node) { ostringstream s; if (! node) s << "NIL"; else { SgNode* father = node->Father(); if (! father) s << '1'; else { s << TreeIndex(father) << '.'; SgNode* son = father->LeftMostSon(); int index = 1; while ((son != node) && son) { ++index; son = son->RightBrother(); } if (son == node) s << index; else SG_ASSERT(false); } } return s.str(); }
SgNode* SgNode::Root() const { SgNode* node = const_cast<SgNode*>(this); while (node->HasFather()) node = node->Father(); return node; }
void SPRAY::ComputeAddressTakenInfo::computeAddressTakenInfo(SgNode* root) { // query to match all SgAddressOfOp subtrees // process query ProcessQuery collectSgAddressOfOp; // TODO: not sufficient to pick up address taken by function pointers std::string matchquery; // "#SgTemplateArgument|" // "#SgTemplateArgumentList|" // "#SgTemplateParameter|" // "#SgTemplateParameterVal|" // "#SgTemplateParamterList|" // skipping all template declaration specific nodes as they dont have any symbols // we still traverse SgTemplateInstatiation* matchquery = \ "#SgTemplateClassDeclaration|"\ "#SgTemplateFunctionDeclaration|"\ "#SgTemplateMemberFunctionDeclaration|"\ "#SgTemplateVariableDeclaration|" \ "#SgTemplateClassDefinition|"\ "#SgTemplateFunctionDefinition|"\ "$HEAD=SgAddressOfOp($OP)"; MatchResult& matches = collectSgAddressOfOp(matchquery, root); for(MatchResult::iterator it = matches.begin(); it != matches.end(); ++it) { SgNode* matchedOperand = (*it)["$OP"]; // SgNode* head = (*it)["$HEAD"]; // debugPrint(head); debugPrint(matchedOperand); OperandToVariableId optovid(*this); matchedOperand->accept(optovid); } }
SgNode* ReplacementMapTraversal::getOriginalNode (const string & key) const { SgNode* duplicateNode = NULL; #if 0 printf ("ReplacementMapTraversal::getOriginalNode: key = %s \n",key.c_str()); printf ("mangledNameMap.size() = %ld \n",mangledNameMap.size()); #endif #if 0 for (MangledNameMapTraversal::MangledNameMapType::iterator i = mangledNameMap.begin(); i != mangledNameMap.end(); i++) { printf ("i->first = %s \n",i->first.c_str()); printf ("i->second = %p \n",i->second); } #endif if (mangledNameMap.find(key) != mangledNameMap.end()) { // This key already exists in the mangledNameMap // duplicateNode = mangledNameMap[key]; // return mangledNameMap[key]; duplicateNode = mangledNameMap[key]; } #if 0 else { // This key does not exist in the mangledNameMap printf ("Warning: This key does not exist in the mangledNameMap, ignoring this case! key = %s \n",key.c_str()); } #endif #if 0 printf ("ReplacementMapTraversal::getOriginalNode() returning duplicateNode = %p = %s \n", duplicateNode,(duplicateNode != NULL) ? duplicateNode->class_name().c_str() : "NULL"); #endif return duplicateNode; }
int main(int argc, char* argv[]) { // This program test the conversion of the ROSE AST to n ATerm and back to a ROSE AST. // Generate a ROSE AST as input. // printf ("Building the ROSE AST \n"); SgProject* project = frontend(argc,argv); // printf ("Done: Building the ROSE AST \n"); // Output an optional graph of the AST (just the tree, when active) // generateDOT(*project); SgFile* roseFile = project->operator[](0); ROSE_ASSERT(roseFile != NULL); SgSourceFile* sourceFile = isSgSourceFile(roseFile); ROSE_ASSERT(sourceFile != NULL); // printf ("Calling ATinit \n"); ATerm bottom; ATinit(argc, argv, &bottom); // printf ("Calling convertAstNodeToRoseAterm \n"); // ATerm term = convertNodeToAterm(project); // ATerm term = convertNodeToAterm(sourceFile); // ATerm term = convertAstNodeToRoseAterm(sourceFile); // Actually this implementation in convertNodeToAterm already adds the pointer value to the aterm, so we can just return this Aterm directly. ATerm term = convertNodeToAterm(sourceFile); // printf ("DONE: Calling convertAstNodeToRoseAterm term = %p \n",term); ROSE_ASSERT (term != NULL); string roseAST_filename = project->get_file(0).getFileName(); char* s = strdup(roseAST_filename.c_str()); string file_basename = basename(s); // ATerm_Graph::graph_aterm_ast(term,file_basename); #if 1 // DQ (9/17/2014): Adding test for conversion of Aterm back to AST. printf ("Testing the reverse process to generate the ROSE AST from the Aterm \n"); SgNode* rootOfAST = convertAtermToNode(term); printf ("rootOfAST = %p = %s \n",rootOfAST,rootOfAST->class_name().c_str()); #endif // generateDOT(*project); generateDOTforMultipleFile(*project, "AFTER_ATERM"); // Output an optional graph of the AST (the whole graph, of bounded complexity, when active) const int MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH = 5000; generateAstGraph(project,MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH,"AFTER_ATERM"); #if 0 printf ("Program Terminated Normally \n"); #endif return 0; }
ATerm AtermSupport::getTraversalChildrenAsAterm(SgNode* n) { // This function is using the same infrastructue used to support the AST traversals, so it // is equivalent in what it traverses and thus properly traverses the defined ROSE AST. vector<SgNode*> children = n->get_traversalSuccessorContainer(); #if 0 printf ("In AtermSupport::getTraversalChildrenAsAterm(): n = %p = %s children.size() = %zu \n",n,n->class_name().c_str(),children.size()); for (vector<SgNode*>::iterator i = children.begin(); i != children.end(); i++) { SgNode* child = *i; printf (" --- child = %p = %s \n",child,(child != NULL) ? child->class_name().c_str() : "NULL"); } #endif // return convertSgNodeRangeToAterm(children.begin(), children.end()); ATerm term = convertSgNodeRangeToAterm(children.begin(), children.end()); // I think we are generating invalid aterms in some cases. #if 0 int atermKind = ATgetType(term); printf ("In AtermSupport::getTraversalChildrenAsAterm(): atermKind = %d = %s \n",atermKind,aterm_type_name(term).c_str()); #endif #if 0 printf ("In AtermSupport::getTraversalChildrenAsAterm(): returning the aterm \n"); #endif #if 0 cout << "AtermSupport::getTraversalChildrenAsAterm(): returning the aterm -> " << ATwriteToString(term) << endl; #endif return term; }
// transfer function // decides if the given pSet is blocked or split or dead // if needs to split, pushes the descendants into splitPSetNodes // if split -> pushes the ConstrGraph corresponding to that into splitConditions bool pCFGIterator::transfer(const pCFGNode& n, unsigned int pSet, const Function& func, NodeState& state, const vector<Lattice*>& dfInfo, bool& isDeadPSet, bool& isSplitPSet, vector<DataflowNode>& splitPSetNodes, bool& isSplitPNode, bool& isBlockPSet, bool& isMergePSet) { bool modified = false; // Get the ROSE_VisitorPattern instance boost::shared_ptr<IntraPCFGTransferVisitor> transferVisitor = boost::shared_ptr<IntraPCFGTransferVisitor> (new pCFGIteratorTransfer (n, pSet, func, state, dfInfo, isDeadPSet, isSplitPSet, splitPSetNodes, isSplitPNode, isBlockPSet, isMergePSet, this->mda)); // get the node on which visitor pattern needs to applied const DataflowNode& dfNode = n.getCurNode(pSet); // get the node SgNode* sgn = dfNode.getNode(); // set the handler sgn->accept(*transferVisitor); modified = transferVisitor->finish() || modified; return modified; }
void loopTraversal::visit(SgNode *node) { Sg_File_Info *info = NULL; SgNode *parent = NULL; info = node->get_file_info(); /* Find code fragment for bottlenecks type 'loop' in C */ if ((isSgForStatement(node)) && (info->get_line() == globals.linenumber)) { /* Found a C loop on the exact line number */ printf("found a loop on (%s:%d) looking for the parent loop\n", info->get_filename(), info->get_line()); parent = node->get_parent(); info = parent->get_file_info(); /* It is a basic block. Who is this basic block's parent? */ if (NULL != isSgBasicBlock(parent)) { parent = parent->get_parent(); } /* Is it a for/do/while? */ if (isSgForStatement(parent)) { /* The parent is a loop */ printf("parent loop found on (%s:%d)\n", info->get_filename(), info->get_line()); /* Do the interchange */ rc = loopInterchange(isSgForStatement(parent), 2, 1); } } }
void CompassAnalyses::DiscardAssignment::Traversal:: visit(SgNode* node) { if (isSgAssignOp(node)) { // simple case: the parent of a "real" assignment op must be an // expression statement if (!isSgExprStatement(node->get_parent())) { output->addOutput(new CheckerOutput(node)); } else { // not so simple case: the parent is an expression statement, but if // that statement is an if/loop condition, we still want to complain SgNode *assignment = node->get_parent(); SgNode *p = assignment->get_parent(); SgDoWhileStmt *dws; SgForStatement *fs; SgIfStmt *is; SgSwitchStatement *ss; SgWhileStmt *ws; if ((dws = isSgDoWhileStmt(p)) && dws->get_condition() == assignment) { output->addOutput(new CheckerOutput(node)); } else if ((fs = isSgForStatement(p)) && fs->get_test() == assignment) { output->addOutput(new CheckerOutput(node)); } else if ((is = isSgIfStmt(p)) && is->get_conditional() == assignment) { output->addOutput(new CheckerOutput(node)); } else if ((ss = isSgSwitchStatement(p)) && ss->get_item_selector() == assignment) { output->addOutput(new CheckerOutput(node)); } else if ((ws = isSgWhileStmt(p)) && ws->get_condition() == assignment) { output->addOutput(new CheckerOutput(node)); } } } else if (SgMemberFunctionRefExp *mf = isSgMemberFunctionRefExp(node)) { // not so simple case: call to operator= member function that is not an // expression statement by itself SgFunctionCallExp *call = isSgFunctionCallExp(mf->get_parent()->get_parent()); if (call && !isSgExprStatement(call->get_parent()) && mf->get_parent() == call->get_function() && std::strcmp(mf->get_symbol()->get_name().str(), "operator=") == 0) { output->addOutput(new CheckerOutput(call)); } } } //End of the visit function.
SgNode* SgNode::TopProp(SgPropID id) const { SgNode* node = const_cast<SgNode*>(this); while (node->HasFather() && ! node->Get(id)) node = node->Father(); // Return either root node or node with property. return node; }
void SgNode::PromotePath() { SgNode* node = this; while (node) { node->PromoteNode(); // promote all nodes on the path to the root node = node->Father(); } }
SgNode* SgNode::LeftBrother() const { if (! HasFather() || ! HasLeftBrother()) return 0; SgNode* node = Father()->LeftMostSon(); // left-most brother while (node->RightBrother() != this) node = node->RightBrother(); return node; }
// Rename all labels in a (possibly inlined) function definition. Gotos to // them will be automatically updated as part of unparsing. void renameLabels(SgNode* fd, SgFunctionDefinition* enclosingFunctionDefinition) { #if 0 SgNode* proj = enclosingFunctionDefinition; while (proj && !isSgProject(proj)) proj = proj->get_parent(); ROSE_ASSERT (isSgProject(proj)); generateAstGraph(isSgProject(proj), 400000); #endif RenameLabelsVisitor(enclosingFunctionDefinition).traverse(fd, preorder); }
SgNode* GoPlayer::TransferSearchTraces() { SgNode* node = m_currentNode; if (node->NumSons() == 0) return 0; m_currentNode = 0; ClearSearchTraces(); return node; }
void HlModel::RenderBones( SgNode *pSkin ) { SgNode *pSkeleton = pSkin->GetJoint(0); while( pSkeleton->pParent() ) { pSkeleton = pSkeleton->pParent(); } RenderChildBones( pSkin->GetWorldTransform(), pSkeleton, pSkeleton->pFirstChild() ); }
SgNode* SgNode::RightMostSon() const { SgNode* node = LeftMostSon(); if (node) { while (node->HasRightBrother()) node = node->RightBrother(); } return node; }
SgNode* SgNode::CopyTree() const { SgNode* newNode = new SgNode(); if (newNode) { newNode->CopyAllPropsFrom(*this); CopySubtree(this, newNode); } return newNode; }
void SgNode::CopySubtree(const SgNode* node, SgNode* copy) { for (const SgNode* son = node->LeftMostSon(); son; son = son->RightBrother()) { SgNode* sonCopy = copy->NewRightMostSon(); sonCopy->CopyAllPropsFrom(*son); CopySubtree(son, sonCopy); } }
bool ClangToSageTranslator::VisitTranslationUnitDecl(clang::TranslationUnitDecl * translation_unit_decl, SgNode ** node) { #if DEBUG_VISIT_DECL std::cerr << "ClangToSageTranslator::VisitTranslationUnitDecl" << std::endl; #endif if (*node != NULL) { std::cerr << "Runtime error: The TranslationUnitDecl is already associated to a SAGE node." << std::endl; return false; } // Create the SAGE node: SgGlobal if (p_global_scope != NULL) { std::cerr << "Runtime error: Global Scope have already been set !" << std::endl; return false; } *node = p_global_scope = new SgGlobal(); p_decl_translation_map.insert(std::pair<clang::Decl *, SgNode *>(translation_unit_decl, p_global_scope)); // Traverse the children SageBuilder::pushScopeStack(*node); clang::DeclContext * decl_context = (clang::DeclContext *)translation_unit_decl; // useless but more clear bool res = true; clang::DeclContext::decl_iterator it; for (it = decl_context->decls_begin(); it != decl_context->decls_end(); it++) { if (*it == NULL) continue; SgNode * child = Traverse(*it); SgDeclarationStatement * decl_stmt = isSgDeclarationStatement(child); if (decl_stmt == NULL && child != NULL) { std::cerr << "Runtime error: the node produce for a clang::Decl is not a SgDeclarationStatement !" << std::endl; std::cerr << " class = " << child->class_name() << std::endl; res = false; } else if (child != NULL) { // FIXME This is a hack to avoid autonomous decl of unnamed type to being added to the global scope.... SgClassDeclaration * class_decl = isSgClassDeclaration(child); if (class_decl != NULL && (class_decl->get_name() == "" || class_decl->get_isUnNamed())) continue; SgEnumDeclaration * enum_decl = isSgEnumDeclaration(child); if (enum_decl != NULL && (enum_decl->get_name() == "" || enum_decl->get_isUnNamed())) continue; p_global_scope->append_declaration(decl_stmt); } } SageBuilder::popScopeStack(); // Traverse the class hierarchy return VisitDecl(translation_unit_decl, node) && res; }
// One match at a time bool pCFGIterator::matchSendRecv(const pCFGNode& pcfgn, set<unsigned int>& sendPSets, set<unsigned int>& recvPSets, set<unsigned int>& blockedPSets, set<unsigned int>& activePSets, set<unsigned int>& releasedPSets) { set<unsigned int>::iterator send_it, recv_it; bool matched = false; for(send_it = sendPSets.begin(); send_it != sendPSets.end(); send_it++) { // try to match each recv for a given send const DataflowNode& dfSend = pcfgn.getCurNode(*send_it); SgNode* sgnSend = dfSend.getNode(); pcfgMatchAnnotation *sendAnnotation = dynamic_cast<pcfgMatchAnnotation*> (sgnSend->getAttribute("pCFGAnnotation")); ROSE_ASSERT(sendAnnotation != NULL); pair<string, int> sendSource = sendAnnotation->getSource(); pair<string, int> sendTarget = sendAnnotation->getTarget(); for(recv_it = recvPSets.begin(); recv_it != recvPSets.end(); recv_it++) { const DataflowNode& dfRecv = pcfgn.getCurNode(*recv_it); SgNode* sgnRecv = dfRecv.getNode(); pcfgMatchAnnotation *recvAnnotation = dynamic_cast<pcfgMatchAnnotation*> (sgnRecv->getAttribute("pCFGAnnotation")); ROSE_ASSERT(recvAnnotation != NULL); pair<string, int> recvSource = recvAnnotation->getSource(); pair<string, int> recvTarget = recvAnnotation->getTarget(); if(sendSource == recvTarget && recvSource == sendTarget) { // we have a match matched = true; break; } } if(matched) break; } if(matched) { int sendPSet = *send_it; int recvPSet = *recv_it; // move send/ recv psets from blocked to active pCFGNode& ref = const_cast<pCFGNode&>(pcfgn); // downgrade the const cast printEdge(ref.getCurAncsNode(sendPSet), ref.getCurAncsNode(recvPSet), "red"); movePSet(sendPSet, activePSets, blockedPSets); movePSet(recvPSet, activePSets, blockedPSets); releasedPSets.insert(sendPSet); releasedPSets.insert(recvPSet); } else { cout << "ERROR: No matches available in blocked state\n"; } return matched; }
void PositionDragger::adjustSize() { BoundingBox bb; for(int i=0; i < numChildren(); ++i){ SgNode* node = child(i); if(node != translationDragger_ && node != rotationDragger_){ bb.expandBy(node->boundingBox()); } } adjustSize(bb); }
SgNode* GoNodeUtil::CreatePosition(int boardSize, SgBlackWhite toPlay, const SgVector<SgPoint>& bPoints, const SgVector<SgPoint>& wPoints) { SgNode* node = new SgNode(); node->Add(new SgPropInt(SG_PROP_SIZE, boardSize)); node->Add(new SgPropPlayer(SG_PROP_PLAYER, toPlay)); node->Add(new SgPropAddStone(SG_PROP_ADD_BLACK, bPoints)); node->Add(new SgPropAddStone(SG_PROP_ADD_WHITE, wPoints)); return node; }