Vuo  2.3.2
VuoCompilerSpecializedNodeClass.cc
Go to the documentation of this file.
1 
10 #include "VuoCompiler.hh"
11 #include "VuoCompilerException.hh"
16 #include "VuoCompilerIssue.hh"
18 #include "VuoCompilerNode.hh"
24 #include "VuoGenericType.hh"
25 #include "VuoNode.hh"
26 #include "VuoNodeClass.hh"
27 #include "VuoNodeSet.hh"
28 #include "VuoPort.hh"
29 #include "VuoStringUtilities.hh"
30 
31 
36  VuoCompilerNodeClass(nodeClassName, module)
37 {
38  initialize();
39 }
40 
45  VuoCompilerNodeClass(compilerNodeClass)
46 {
47  initialize();
48 }
49 
54  VuoCompilerNodeClass(baseNodeClass)
55 {
56  initialize();
57 }
58 
62 void VuoCompilerSpecializedNodeClass::initialize(void)
63 {
64  genericNodeClass = NULL;
65  backingNodeClass = NULL;
66 }
67 
79 VuoNodeClass * VuoCompilerSpecializedNodeClass::newNodeClass(const string &nodeClassName, VuoCompiler *compiler, dispatch_queue_t llvmQueue)
80 {
81  if (nodeClassName.find(".") == string::npos)
82  return NULL;
83 
84  VuoNodeClass *makeListNodeClass = VuoCompilerMakeListNodeClass::newNodeClass(nodeClassName, compiler, llvmQueue);
85  if (makeListNodeClass)
86  return makeListNodeClass;
87 
88  VuoNodeClass *publishedInputNodeClass = VuoCompilerPublishedInputNodeClass::newNodeClass(nodeClassName, compiler, llvmQueue);
89  if (publishedInputNodeClass)
90  return publishedInputNodeClass;
91 
92  VuoNodeClass *publishedOutputNodeClass = VuoCompilerPublishedOutputNodeClass::newNodeClass(nodeClassName, compiler, llvmQueue);
93  if (publishedOutputNodeClass)
94  return publishedOutputNodeClass;
95 
96 
97  // Find the generic node class that the given node class should specialize
98 
99  VuoCompilerNodeClass *potentialGenericNodeClass = NULL;
100  vector<string> parts = VuoStringUtilities::split(nodeClassName, '.');
101  for (int j = parts.size() - 1; j >= 1; --j)
102  {
103  string newLastPart = parts[j];
104  if (! compiler->getType(newLastPart))
105  break;
106 
107  vector<string> firstParts(parts.begin(), parts.begin() + j);
108  string potentialGenericNodeClassName = VuoStringUtilities::join(firstParts, '.');
109 
110  potentialGenericNodeClass = compiler->getNodeClass(potentialGenericNodeClassName);
111  if (potentialGenericNodeClass)
112  break;
113  }
114 
115  VuoCompilerNodeClass *genericNodeClass = NULL;
116  vector<string> genericTypeNames;
117  if (potentialGenericNodeClass)
118  {
119  vector<string> potentialGenericTypeNames = getGenericTypeNamesFromPorts(potentialGenericNodeClass);
120  string expectedGenericNodeClassName = extractGenericNodeClassName(nodeClassName, potentialGenericTypeNames.size());
121  if (expectedGenericNodeClassName == potentialGenericNodeClass->getBase()->getClassName())
122  {
123  genericNodeClass = potentialGenericNodeClass;
124  genericTypeNames = potentialGenericTypeNames;
125  }
126  }
127 
128  if (! genericNodeClass)
129  return NULL;
130 
131 
132  // Map the generic types (found in ports) to the specialized types (found in the node class name)
133 
134  vector<string> nodeClassNameParts = VuoStringUtilities::split(nodeClassName, '.');
135  vector<string> specializedTypeNames(nodeClassNameParts.begin() + nodeClassNameParts.size() - genericTypeNames.size(), nodeClassNameParts.end());
136 
137  map<string, string> specializedForGenericTypeName;
138  bool _isFullySpecialized = true;
139  for (size_t i = 0; i < genericTypeNames.size(); ++i)
140  {
141  if (VuoGenericType::isGenericTypeName( specializedTypeNames[i] ))
142  _isFullySpecialized = false;
143  else if (! compiler->getType( specializedTypeNames[i] ))
144  return NULL;
145 
146  specializedForGenericTypeName[ genericTypeNames[i] ] = specializedTypeNames[i];
147  }
148 
149 
150  __block VuoCompilerSpecializedNodeClass *nodeClass;
151 
152  if (_isFullySpecialized)
153  {
154  // Compile the specialized node class (with any necessary headers for types)
155 
156  string genericNodeClassName = genericNodeClass->getBase()->getClassName();
157  string genericImplementation = genericNodeClass->getBase()->getNodeSet()
158  ? genericNodeClass->getBase()->getNodeSet()->getNodeClassContents( genericNodeClassName )
159  : genericNodeClass->getSourceCode();
160  if (genericImplementation.empty())
161  {
162  VuoCompilerIssue issue(VuoCompilerIssue::Error, "specializing node in composition", "",
163  "Missing source code",
164  "%module uses generic types, but its source code isn't included in its node set. "
165  "If you are the author of this node, see the API documentation section \"Generic port types\" "
166  "under \"Developing a node class\" (https://api.vuo.org/latest/group___developing_node_classes.html). "
167  "Otherwise, contact the author of this node.");
168  issue.setModule(genericNodeClass->getBase());
169  throw VuoCompilerException(issue);
170  }
171  genericImplementation.insert(VuoFileUtilities::getFirstInsertionIndex(genericImplementation), "#define VuoSpecializedNode 1\n");
172 
173  string tmpDir = VuoFileUtilities::makeTmpDir(nodeClassName);
174 
175  replaceGenericTypesWithSpecialized(genericImplementation, specializedForGenericTypeName);
176 
177  string tmpNodeClassImplementationFile = tmpDir + "/" + nodeClassName + ".c";
178  string tmpNodeClassCompiledFile = tmpDir + "/" + nodeClassName + ".vuonode";
179  VuoFileUtilities::preserveOriginalFileName(genericImplementation, genericNodeClassName + ".c");
180  VuoFileUtilities::writeStringToFile(genericImplementation, tmpNodeClassImplementationFile);
181 
182  set<VuoNodeSet *> nodeSetDependencies;
183  VuoNodeSet *genericNodeSet = genericNodeClass->getBase()->getNodeSet();
184  if (genericNodeSet)
185  {
186  nodeSetDependencies.insert(genericNodeSet);
187  }
188  for (vector<string>::iterator i = specializedTypeNames.begin(); i != specializedTypeNames.end(); ++i)
189  {
190  string specializedTypeName = *i;
191  if (VuoGenericType::isGenericTypeName(specializedTypeName))
192  continue;
193 
194  string innermostTypeName = VuoType::extractInnermostTypeName(specializedTypeName);
195  VuoNodeSet *typeNodeSet = compiler->getType(innermostTypeName)->getBase()->getNodeSet();
196  if (typeNodeSet)
197  nodeSetDependencies.insert(typeNodeSet);
198  }
199  set<string> tmpHeaders;
200  for (set<VuoNodeSet *>::iterator i = nodeSetDependencies.begin(); i != nodeSetDependencies.end(); ++i)
201  {
202  VuoNodeSet *nodeSet = *i;
203  vector<string> headerFileNames = nodeSet->getHeaderFileNames();
204  for (vector<string>::iterator j = headerFileNames.begin(); j != headerFileNames.end(); ++j)
205  {
206  string headerFileName = *j;
207  string header = nodeSet->getHeaderContents( headerFileName );
208  string tmpHeaderFile = tmpDir + "/" + headerFileName;
209  VuoFileUtilities::writeStringToFile(header, tmpHeaderFile);
210  tmpHeaders.insert(tmpHeaderFile);
211  }
212  }
213  vector<string> includeDirs;
214  includeDirs.push_back(tmpDir);
215 
216  compiler->compileModule(tmpNodeClassImplementationFile, tmpNodeClassCompiledFile, includeDirs);
217  Module *module = compiler->readModuleFromBitcode(tmpNodeClassCompiledFile, compiler->getArch());
218 
219  for (set<string>::iterator i = tmpHeaders.begin(); i != tmpHeaders.end(); ++i)
220  remove((*i).c_str());
221  remove(tmpNodeClassImplementationFile.c_str());
222  remove(tmpNodeClassCompiledFile.c_str());
223  remove(tmpDir.c_str());
224 
225 
226  // Construct the VuoCompilerSpecializedNodeClass
227 
228  dispatch_sync(llvmQueue, ^{
229  VuoCompilerSpecializedNodeClass *dummyNodeClass = new VuoCompilerSpecializedNodeClass(nodeClassName, module);
230  nodeClass = new VuoCompilerSpecializedNodeClass(dummyNodeClass);
231  delete dummyNodeClass;
232  });
233  }
234  else
235  {
236  // Construct a node class that doesn't yet have an implementation, using the generic node class as the model.
237 
238  vector<VuoPortClass *> modelInputPortClasses = genericNodeClass->getBase()->getInputPortClasses();
239  vector<VuoPortClass *> inputPortClasses;
240  for (VuoPortClass *modelPortClass : modelInputPortClasses)
241  {
242  VuoPortClass *portClass = copyPortClassFromModel(modelPortClass, true);
243  inputPortClasses.push_back(portClass);
244  }
245 
246  vector<VuoPortClass *> modelOutputPortClasses = genericNodeClass->getBase()->getOutputPortClasses();
247  vector<VuoPortClass *> outputPortClasses;
248  for (VuoPortClass *modelPortClass : modelOutputPortClasses)
249  {
250  VuoPortClass *portClass = copyPortClassFromModel(modelPortClass, false);
251  outputPortClasses.push_back(portClass);
252  }
253 
254  vector<VuoPortClass *> modelPortClasses;
255  modelPortClasses.insert(modelPortClasses.end(), modelInputPortClasses.begin(), modelInputPortClasses.end());
256  modelPortClasses.insert(modelPortClasses.end(), modelOutputPortClasses.begin(), modelOutputPortClasses.end());
257  vector<VuoPortClass *> portClasses;
258  portClasses.insert(portClasses.end(), inputPortClasses.begin(), inputPortClasses.end());
259  portClasses.insert(portClasses.end(), outputPortClasses.begin(), outputPortClasses.end());
260  for (size_t i = 0; i < modelPortClasses.size(); ++i)
261  {
262  VuoCompilerPortClass *modelPortClass = static_cast<VuoCompilerPortClass *>( modelPortClasses[i]->getCompiler() );
263  VuoCompilerPortClass *portClass = static_cast<VuoCompilerPortClass *>( portClasses[i]->getCompiler() );
264  VuoType *modelPortType = modelPortClass->getDataVuoType();
265  if (modelPortType)
266  {
267  string modelPortTypeName = modelPortType->getModuleKey();
268  string innermostModelPortTypeName = VuoType::extractInnermostTypeName(modelPortTypeName);
269  map<string, string>::iterator specializedTypeNameIter = specializedForGenericTypeName.find(innermostModelPortTypeName);
270  if (specializedTypeNameIter != specializedForGenericTypeName.end())
271  {
272  string innermostSpecializedTypeName = specializedTypeNameIter->second;
273  if (innermostSpecializedTypeName != innermostModelPortTypeName)
274  {
275  string specializedTypeName = VuoGenericType::replaceInnermostGenericTypeName(modelPortTypeName, innermostSpecializedTypeName);
276  VuoType *portType = compiler->getType(specializedTypeName)->getBase();
277  portClass->setDataVuoType(portType);
278  }
279  }
280  }
281  }
282 
283  VuoPortClass *refreshPortClass = inputPortClasses.front();
284 
285  VuoNodeClass *baseNodeClass = new VuoNodeClass(nodeClassName, refreshPortClass, inputPortClasses, outputPortClasses);
286  nodeClass = new VuoCompilerSpecializedNodeClass(baseNodeClass);
287 
288  baseNodeClass->setDefaultTitle(genericNodeClass->getBase()->getDefaultTitle());
289  baseNodeClass->setDescription(genericNodeClass->getBase()->getDescription());
290  baseNodeClass->setVersion(genericNodeClass->getBase()->getVersion());
291  baseNodeClass->setKeywords(genericNodeClass->getBase()->getKeywords());
292  baseNodeClass->setNodeSet(genericNodeClass->getBase()->getNodeSet());
293  baseNodeClass->setExampleCompositionFileNames(genericNodeClass->getBase()->getExampleCompositionFileNames());
294  baseNodeClass->setDeprecated(genericNodeClass->getBase()->getDeprecated());
295 
296  for (vector<string>::iterator i = genericTypeNames.begin(); i != genericTypeNames.end(); ++i)
297  {
298  string genericTypeName = *i;
299  string defaultSpecializedTypeName = genericNodeClass->getDefaultSpecializedTypeName(*i);
300  if (! defaultSpecializedTypeName.empty())
301  nodeClass->defaultSpecializedForGenericTypeName[genericTypeName] = defaultSpecializedTypeName;
302  }
303 
304  // The compiler will assign a fully-specialized backing node class with updateBackingNodeClass(), but
305  // the renderer may need a backing node class before then, e.g. to know if the node is stateful.
306  nodeClass->backingNodeClass = genericNodeClass;
307  }
308 
309  nodeClass->genericNodeClass = genericNodeClass;
310  nodeClass->specializedForGenericTypeName = specializedForGenericTypeName;
311 
312  nodeClass->setBuiltIn( genericNodeClass->isBuiltIn() );
313 
314  return nodeClass->getBase();
315 }
316 
321 {
322  string name = modelPortClass->getName();
323  VuoPortClass::PortType portType = modelPortClass->getPortType();
324 
325  VuoCompilerPortClass *modelCompilerPortClass = static_cast<VuoCompilerPortClass *>(modelPortClass->getCompiler());
326  VuoType *dataType = modelCompilerPortClass->getDataVuoType();
327 
328  VuoCompilerPortClass *portClass = nullptr;
329  if (isInput)
330  {
332  portClass = inputPortClass;
333 
334  if (dataType)
335  {
336  VuoCompilerInputDataClass *inputDataClass = new VuoCompilerInputDataClass("");
337  inputPortClass->setDataClass(inputDataClass);
338  }
339  }
340  else
341  {
342  if (portType == VuoPortClass::eventOnlyPort || portType == VuoPortClass::dataAndEventPort)
343  {
345  portClass = outputPortClass;
346 
347  if (dataType)
348  {
349  VuoCompilerOutputDataClass *outputDataClass = new VuoCompilerOutputDataClass("");
350  outputPortClass->setDataClass(outputDataClass);
351  }
352  }
353  else if (portType == VuoPortClass::triggerPort)
354  {
355  VuoCompilerTriggerPortClass *triggerPortClass = new VuoCompilerTriggerPortClass(name);
356  portClass = triggerPortClass;
357  }
358  }
359 
360  if ((portType == VuoPortClass::eventOnlyPort || portType == VuoPortClass::dataAndEventPort) && dataType)
361  {
362  VuoCompilerEventPortClass *modelEventPortClass = static_cast<VuoCompilerEventPortClass *>(modelCompilerPortClass);
363  VuoCompilerEventPortClass *eventPortClass = static_cast<VuoCompilerEventPortClass *>(portClass);
364  json_object *dataDetails = modelEventPortClass->getDataClass()->getDetails();
365  eventPortClass->getDataClass()->setDetails(dataDetails);
366  json_object_get(dataDetails);
367  }
368 
369  if (dataType)
370  portClass->setDataVuoType(dataType);
371 
372  json_object *details = modelCompilerPortClass->getDetails();
373  portClass->setDetails(details);
374  json_object_get(details);
375 
376  portClass->getBase()->setEventBlocking(modelPortClass->getEventBlocking());
377  portClass->getBase()->setPortAction(modelPortClass->hasPortAction());
378  portClass->getBase()->setDefaultEventThrottling(modelPortClass->getDefaultEventThrottling());
379 
380  return portClass->getBase();
381 }
382 
395 {
396  vector<string> genericTypes = getGenericTypeNamesFromPorts(origNodeClass);
397  if (! genericTypes.empty())
398  {
399  VuoCompilerSpecializedNodeClass *specializedNodeClass = dynamic_cast<VuoCompilerSpecializedNodeClass *>(origNodeClass);
400  if (specializedNodeClass)
401  {
402  return newNodeClass(origNodeClass->getBase()->getClassName(), compiler, NULL)->getCompiler();
403  }
404  else
405  {
406  string rawGenericNodeClassName = origNodeClass->getBase()->getClassName();
407  string rawGenericNodeClassNameWithSuffixes = createSpecializedNodeClassName(rawGenericNodeClassName, genericTypes);
408  VuoCompilerNodeClass *rawGenericNodeClassUncasted = newNodeClass(rawGenericNodeClassNameWithSuffixes, compiler, NULL)->getCompiler();
409  VuoCompilerSpecializedNodeClass *rawGenericNodeClass = static_cast<VuoCompilerSpecializedNodeClass *>(rawGenericNodeClassUncasted);
410  string genericNodeClassName = rawGenericNodeClass->createDefaultSpecializedNodeClassName();
411  return compiler->getNodeClass(genericNodeClassName);
412  }
413  }
414 
415  return origNodeClass;
416 }
417 
421 bool VuoCompilerSpecializedNodeClass::isSpecializationOfNodeClass(const string &potentialSpecializedNodeClassName,
422  VuoCompilerNodeClass *potentialGenericNodeClass)
423 {
424  vector<string> genericTypesFromGeneric = getGenericTypeNamesFromPorts(potentialGenericNodeClass);
425  if (genericTypesFromGeneric.empty())
426  return false;
427 
428  string genericNodeClassNameFromSpecialized = extractGenericNodeClassName(potentialSpecializedNodeClassName, genericTypesFromGeneric.size());
429  return genericNodeClassNameFromSpecialized == potentialGenericNodeClass->getBase()->getClassName();
430 }
431 
437 {
438  string backingNodeClassName = createFullySpecializedNodeClassName(nodeToBack);
439  if (backingNodeClassName == getBase()->getClassName() ||
440  (backingNodeClass && backingNodeClassName == backingNodeClass->getBase()->getClassName()))
441  return;
442 
443  VuoCompilerNode *replacementCompilerNode = createReplacementBackingNode(nodeToBack, backingNodeClassName, compiler);
444  replacementCompilerNode->setGraphvizIdentifier( nodeToBack->getCompiler()->getGraphvizIdentifier() );
445 
446  backingNodeClass = replacementCompilerNode->getBase()->getNodeClass()->getCompiler();
447 
448  // Transfer each VuoCompilerPort from the replacement to nodeToBack.
449  vector<VuoPort *> inputPortsOnReplacementNode = replacementCompilerNode->getBase()->getInputPorts();
450  vector<VuoPort *> inputPortsOnNodeToBack = nodeToBack->getInputPorts();
451  vector<VuoPort *> outputPortsOnReplacementNode = replacementCompilerNode->getBase()->getOutputPorts();
452  vector<VuoPort *> outputPortsOnNodeToBack = nodeToBack->getOutputPorts();
453  vector<VuoPort *> portsOnReplacementNode;
454  vector<VuoPort *> portsOnNodeToBack;
455  portsOnReplacementNode.insert(portsOnReplacementNode.end(), inputPortsOnReplacementNode.begin(), inputPortsOnReplacementNode.end());
456  portsOnReplacementNode.insert(portsOnReplacementNode.end(), outputPortsOnReplacementNode.begin(), outputPortsOnReplacementNode.end());
457  portsOnNodeToBack.insert(portsOnNodeToBack.end(), inputPortsOnNodeToBack.begin(), inputPortsOnNodeToBack.end());
458  portsOnNodeToBack.insert(portsOnNodeToBack.end(), outputPortsOnNodeToBack.begin(), outputPortsOnNodeToBack.end());
459  for (int i = 0; i < inputPortsOnReplacementNode.size(); ++i)
460  {
461  VuoCompilerInputEventPort *port = dynamic_cast<VuoCompilerInputEventPort *>(inputPortsOnNodeToBack[i]->getCompiler());
462  VuoCompilerInputEventPort *replacementPort = dynamic_cast<VuoCompilerInputEventPort *>(inputPortsOnReplacementNode[i]->getCompiler());
463  if (port->getData())
464  replacementPort->getData()->setInitialValue( port->getData()->getInitialValue() );
465  }
466  for (int i = 0; i < portsOnReplacementNode.size(); ++i)
467  {
468  VuoPort *baseToKeep = portsOnNodeToBack[i];
469  VuoCompilerNodeArgument *compilerPortToKeep = portsOnReplacementNode[i]->getCompiler();
470  VuoCompilerNodeArgumentClass *compilerPortClassToKeep = portsOnReplacementNode[i]->getClass()->getCompiler();
471  baseToKeep->setCompiler(compilerPortToKeep);
472  baseToKeep->getClass()->setCompiler(compilerPortClassToKeep);
473  compilerPortToKeep->setBase(baseToKeep);
474  compilerPortClassToKeep->setBase(baseToKeep->getClass());
475  }
476 
477  // Transfer the VuoCompilerNode from the replacement to nodeToBack.
478  VuoNode *baseToDiscard = replacementCompilerNode->getBase();
479  VuoCompilerNode *compilerToDiscard = nodeToBack->getCompiler();
480  nodeToBack->setCompiler(replacementCompilerNode);
481  replacementCompilerNode->setBase(nodeToBack);
482  delete baseToDiscard;
483  delete compilerToDiscard;
484 }
485 
490 {
491  VuoCompilerNodeClass *nodeClass = compiler->getNodeClass(backingNodeClassName);
492  if (!nodeClass)
493  throw VuoCompilerException(VuoCompilerIssue(VuoCompilerIssue::Error, "specializing node in composition", "",
494  "Couldn't get backing node class.",
495  "'" + backingNodeClassName + "' uses generic types, but it couldn't be compiled. "
496  "Check the macOS Console for details."));
497  return nodeClass->newNode(nodeToBack)->getCompiler();
498 }
499 
504 void VuoCompilerSpecializedNodeClass::replaceGenericTypesWithSpecialized(string &nodeClassSource, map<string, string> specializedForGenericTypeName)
505 {
506  set<string> replacementTypeNames;
507  for (map<string, string>::iterator i = specializedForGenericTypeName.begin(); i != specializedForGenericTypeName.end(); ++i)
508  {
509  string genericTypeName = i->first;
510  string replacementTypeName = i->second;
511 
512  if (replacementTypeName != genericTypeName)
513  {
514  // Replace each occurrence of the generic type name with the specialized or backing type name.
515  VuoStringUtilities::replaceAll(nodeClassSource, genericTypeName, replacementTypeName);
516 
517  string innermostTypeName = VuoType::extractInnermostTypeName(replacementTypeName);
518  replacementTypeNames.insert(innermostTypeName);
519  }
520  }
521 
522  string includesToAdd;
523  for (set<string>::iterator i = replacementTypeNames.begin(); i != replacementTypeNames.end(); ++i)
524  {
525  string replacementTypeName = *i;
526  includesToAdd += "#include \"" + replacementTypeName + ".h\"\n";
527 
528  if (nodeClassSource.find(VuoType::listTypeNamePrefix + replacementTypeName) != string::npos)
529  includesToAdd += "#include \"" + VuoType::listTypeNamePrefix + replacementTypeName + ".h\"\n";
530  }
531 
532  size_t insertionPos = nodeClassSource.find("VuoModuleMetadata"); // assumed to be after '#include "node.h"' and before any generic type names
533  if (insertionPos == string::npos)
534  return;
535  nodeClassSource.insert(insertionPos, includesToAdd);
536 }
537 
542 {
543  size_t insertionPos = nodeClassSource.find("VuoModuleMetadata"); // assumed to be after '#include "node.h"' and before any generic type identifiers
544  if (insertionPos == string::npos)
545  return;
546 
547  map<string, vector<string> > compatibleTypesForGeneric;
548 
549  // Figure out the backing types by parsing the "genericTypes" metadata from nodeClassSource.
550  size_t metadataStartPos = nodeClassSource.find("(", insertionPos) + 1;
551  if (metadataStartPos == string::npos)
552  return;
553  size_t metadataEndPos = nodeClassSource.find(");\n", metadataStartPos);
554  if (metadataEndPos == string::npos)
555  return;
556  string moduleMetadataString = nodeClassSource.substr(metadataStartPos, metadataEndPos - metadataStartPos);
557  json_object *moduleMetadata = json_tokener_parse(moduleMetadataString.c_str());
558  if (! moduleMetadata)
559  return;
560  map<string, string> defaultTypeForGeneric;
561  VuoCompilerNodeClass::parseGenericTypes(moduleMetadata, defaultTypeForGeneric, compatibleTypesForGeneric);
562  json_object_put(moduleMetadata);
563 
564  set<string> genericTypeIdentifiers;
565  size_t startPos = 0;
566  string genericTypeName;
567  while ((startPos = VuoGenericType::findGenericTypeName(nodeClassSource, startPos, genericTypeName)) != string::npos)
568  {
569  size_t endPos = startPos + genericTypeName.length();
570  if ((startPos == 0 || ! VuoStringUtilities::isValidCharInIdentifier( nodeClassSource[startPos-1] )) &&
571  (endPos == nodeClassSource.length() - 1 || ! VuoStringUtilities::isValidCharInIdentifier( nodeClassSource[endPos] )))
572  {
573  // Found a generic type identifier, so prepare to add a typedef.
574  genericTypeIdentifiers.insert(genericTypeName);
575  startPos += genericTypeName.length();
576  }
577  else
578  {
579  // Found a generic type name within another identifier, so replace it with its backing type name.
580  string innermostTypeName = VuoType::extractInnermostTypeName(genericTypeName);
581  string innermostBackingTypeName = VuoCompilerGenericType::chooseBackingTypeName(genericTypeName,
582  compatibleTypesForGeneric[innermostTypeName]);
583  string backingTypeName = VuoGenericType::replaceInnermostGenericTypeName(genericTypeName, innermostBackingTypeName);
584  nodeClassSource.replace(startPos, genericTypeName.length(), backingTypeName);
585  startPos += backingTypeName.length();
586  }
587  }
588 
589  // Add a typedef to replace each generic type with its backing type.
590  string typedefsToAdd;
591  map<string, bool> typeNamesSeen;
592  for (set<string>::iterator i = genericTypeIdentifiers.begin(); i != genericTypeIdentifiers.end(); ++i)
593  {
594  string genericTypeName = *i;
595 
596  string innermostTypeName = VuoType::extractInnermostTypeName(genericTypeName);
597  string innermostBackingTypeName = VuoCompilerGenericType::chooseBackingTypeName(innermostTypeName,
598  compatibleTypesForGeneric[innermostTypeName]);
599  if (! typeNamesSeen[innermostTypeName])
600  {
601  typeNamesSeen[innermostTypeName] = true;
602 
603  string replacementTypeName = innermostBackingTypeName;
604  typedefsToAdd += "typedef " + replacementTypeName + " " + innermostTypeName + ";\n";
605  }
606 
607  if (! typeNamesSeen[genericTypeName])
608  {
609  typeNamesSeen[genericTypeName] = true;
610 
611  string replacementCollectionTypeName = VuoGenericType::replaceInnermostGenericTypeName(genericTypeName, innermostBackingTypeName);
612  typedefsToAdd += "typedef " + replacementCollectionTypeName + " " + genericTypeName + ";\n";
613  }
614  }
615  nodeClassSource.insert(insertionPos, typedefsToAdd);
616 }
617 
622 {
623  return getGenericTypeNamesFromPorts(this).empty();
624 }
625 
630 {
631  return ! getGenericTypeNamesFromPorts(nodeClass).empty();
632 }
633 
637 vector<string> VuoCompilerSpecializedNodeClass::getGenericTypeNamesFromPorts(VuoCompilerNodeClass *nodeClass)
638 {
639  set<string> genericTypeNames;
640  vector<VuoPortClass *> inputPortClasses = nodeClass->getBase()->getInputPortClasses();
641  vector<VuoPortClass *> outputPortClasses = nodeClass->getBase()->getOutputPortClasses();
642  vector<VuoPortClass *> portClasses;
643  portClasses.insert(portClasses.end(), inputPortClasses.begin(), inputPortClasses.end());
644  portClasses.insert(portClasses.end(), outputPortClasses.begin(), outputPortClasses.end());
645  for (vector<VuoPortClass *>::iterator i = portClasses.begin(); i != portClasses.end(); ++i)
646  {
647  VuoCompilerPortClass *portClass = static_cast<VuoCompilerPortClass *>((*i)->getCompiler());
648  VuoGenericType *genericType = dynamic_cast<VuoGenericType *>(portClass->getDataVuoType());
649  if (genericType)
650  {
651  string innermostTypeName = VuoType::extractInnermostTypeName(genericType->getModuleKey());
652  genericTypeNames.insert(innermostTypeName);
653  }
654  }
655 
656  vector<string> sortedGenericTypeNames(genericTypeNames.begin(), genericTypeNames.end());
657  VuoGenericType::sortGenericTypeNames(sortedGenericTypeNames);
658  return sortedGenericTypeNames;
659 }
660 
667 map<string, string> VuoCompilerSpecializedNodeClass::getBackingTypeNamesFromPorts(VuoNode *node)
668 {
669  map<string, string> backingTypeForPort;
670 
671  vector<VuoPort *> inputPorts = node->getInputPorts();
672  vector<VuoPort *> outputPorts = node->getOutputPorts();
673  vector<VuoPort *> ports;
674  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
675  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
676  for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
677  {
678  VuoCompilerPort *port = static_cast<VuoCompilerPort *>((*i)->getCompiler());
679  VuoType *type = port->getDataVuoType();
680  if (! type || ! type->hasCompiler())
681  continue;
682 
683  VuoCompilerGenericType *genericTypeForPort = dynamic_cast<VuoCompilerGenericType *>(type->getCompiler());
684  if (! genericTypeForPort)
685  continue;
686  string backingTypeName = genericTypeForPort->getBackingTypeName();
687 
688  VuoCompilerPortClass *portClass = static_cast<VuoCompilerPortClass *>((*i)->getClass()->getCompiler());
689  string genericTypeNameForPortClass = portClass->getDataVuoType()->getModuleKey();
690 
691  string innermostGenericTypeName = VuoType::extractInnermostTypeName( genericTypeNameForPortClass );
692  string innermostBackingTypeName = VuoType::extractInnermostTypeName( backingTypeName );
693  backingTypeForPort[innermostGenericTypeName] = innermostBackingTypeName;
694  }
695 
696  return backingTypeForPort;
697 }
698 
703 {
704  int i = 0;
705  for (auto specializedPortClass : getBase()->getInputPortClasses())
706  {
707  if (specializedPortClass == portClass)
708  return static_cast<VuoCompilerPortClass *>(genericNodeClass->getBase()->getInputPortClasses()[i]->getCompiler())->getDataVuoType();
709  ++i;
710  }
711 
712  i = 0;
713  for (auto specializedPortClass : getBase()->getOutputPortClasses())
714  {
715  if (specializedPortClass == portClass)
716  return static_cast<VuoCompilerPortClass *>(genericNodeClass->getBase()->getOutputPortClasses()[i]->getCompiler())->getDataVuoType();
717  ++i;
718  }
719 
720  return nullptr;
721 }
722 
727 {
728  return genericNodeClass->getBase()->getModuleKey();
729 }
730 
735 {
736  return genericNodeClass->getBase()->getDescription();
737 }
738 
743 {
744  return genericNodeClass->getBase()->getNodeSet();
745 }
746 
750 string VuoCompilerSpecializedNodeClass::createUnspecializedNodeClassName(set<VuoPortClass *> portClassesToUnspecialize)
751 {
752  set<string> genericTypeNames;
753  for (set<VuoPortClass *>::iterator i = portClassesToUnspecialize.begin(); i != portClassesToUnspecialize.end(); ++i)
754  {
755  VuoPortClass *portClassToUnspecialize = *i;
756  VuoGenericType *genericType = dynamic_cast<VuoGenericType *>( getOriginalPortType(portClassToUnspecialize) );
757  if (genericType)
758  {
759  string innermostGenericTypeName = VuoType::extractInnermostTypeName(genericType->getModuleKey());
760  genericTypeNames.insert(innermostGenericTypeName);
761  }
762  }
763 
764  vector<string> specializedTypeNames;
765  vector<string> origGenericTypeNames = getGenericTypeNamesFromPorts(genericNodeClass);
766  for (vector<string>::iterator i = origGenericTypeNames.begin(); i != origGenericTypeNames.end(); ++i)
767  {
768  string g = *i;
769  string s = (genericTypeNames.find(g) != genericTypeNames.end() ? g : specializedForGenericTypeName[g]);
770  specializedTypeNames.push_back(s);
771  }
772 
773  string genericNodeClassName = extractGenericNodeClassName(getBase()->getClassName(), origGenericTypeNames.size());
774  return createSpecializedNodeClassName(genericNodeClassName, specializedTypeNames);
775 }
776 
781 string VuoCompilerSpecializedNodeClass::createSpecializedNodeClassNameWithReplacement(string genericTypeName, string specializedTypeName)
782 {
783  vector<string> specializedTypeNames;
784  vector<string> origGenericTypeNames = getGenericTypeNamesFromPorts(genericNodeClass);
785  for (vector<string>::iterator i = origGenericTypeNames.begin(); i != origGenericTypeNames.end(); ++i)
786  {
787  string g = *i;
788  string s = (g == genericTypeName ? specializedTypeName : specializedForGenericTypeName[g]);
789  specializedTypeNames.push_back(s);
790  }
791 
792  string genericNodeClassName = extractGenericNodeClassName(getBase()->getClassName(), origGenericTypeNames.size());
793  return createSpecializedNodeClassName(genericNodeClassName, specializedTypeNames);
794 }
795 
800 string VuoCompilerSpecializedNodeClass::createDefaultSpecializedNodeClassName(void)
801 {
802  vector<string> sortedGenericTypeNames = getGenericTypeNamesFromPorts(this);
803  vector<string> sortedSpecializedTypeNames;
804  for (vector<string>::iterator i = sortedGenericTypeNames.begin(); i != sortedGenericTypeNames.end(); ++i)
805  {
806  string genericTypeName = *i;
807  map<string, string>::iterator defaultTypeNameIter = defaultSpecializedForGenericTypeName.find(genericTypeName);
808  string specializedTypeName = (defaultTypeNameIter != defaultSpecializedForGenericTypeName.end() ?
809  defaultTypeNameIter->second : genericTypeName);
810  sortedSpecializedTypeNames.push_back(specializedTypeName);
811  }
812 
813  string genericNodeClassName = extractGenericNodeClassName(getBase()->getClassName(), sortedGenericTypeNames.size());
814  return createSpecializedNodeClassName(genericNodeClassName, sortedSpecializedTypeNames);
815 }
816 
821 string VuoCompilerSpecializedNodeClass::createFullySpecializedNodeClassName(VuoNode *nodeToBack)
822 {
823  map<string, string> backingForGeneric = getBackingTypeNamesFromPorts(nodeToBack);
824 
825  vector<string> nodeClassNameParts = VuoStringUtilities::split(getBase()->getClassName(), '.');
826  for (int i = 1; i < nodeClassNameParts.size(); ++i)
827  {
828  map<string, string>::iterator backingIter = backingForGeneric.find( VuoType::extractInnermostTypeName(nodeClassNameParts[i]) );
829  if (backingIter != backingForGeneric.end())
830  nodeClassNameParts[i] = VuoGenericType::replaceInnermostGenericTypeName(nodeClassNameParts[i], backingIter->second);
831  }
832 
833  return VuoStringUtilities::join(nodeClassNameParts, '.');
834 }
835 
839 string VuoCompilerSpecializedNodeClass::extractGenericNodeClassName(string specializedNodeClassName, size_t genericTypeCount)
840 {
841  vector<string> specializedNameParts = VuoStringUtilities::split(specializedNodeClassName, '.');
842  if (specializedNameParts.size() < 2 + genericTypeCount)
843  return "";
844 
845  vector<string> genericNameParts(specializedNameParts.begin(), specializedNameParts.begin() + specializedNameParts.size() - genericTypeCount);
846  return VuoStringUtilities::join(genericNameParts, '.');
847 }
848 
852 string VuoCompilerSpecializedNodeClass::createSpecializedNodeClassName(string genericNodeClassName, vector<string> specializedTypeNames)
853 {
854  return genericNodeClassName + '.' + VuoStringUtilities::join(specializedTypeNames, '.');
855 }
856 
858 
861 string VuoCompilerSpecializedNodeClass::getClassIdentifier(void)
862 { return backingNodeClass ? backingNodeClass->getClassIdentifier() : VuoCompilerNodeClass::getClassIdentifier(); }
863 
864 Function * VuoCompilerSpecializedNodeClass::getEventFunction(void)
865 { return backingNodeClass ? backingNodeClass->getEventFunction() : VuoCompilerNodeClass::getEventFunction(); }
866 
867 Function * VuoCompilerSpecializedNodeClass::getInitFunction(void)
868 { return backingNodeClass ? backingNodeClass->getInitFunction() : VuoCompilerNodeClass::getInitFunction(); }
869 
870 Function * VuoCompilerSpecializedNodeClass::getFiniFunction(void)
871 { return backingNodeClass ? backingNodeClass->getFiniFunction() : VuoCompilerNodeClass::getFiniFunction(); }
872 
873 Function * VuoCompilerSpecializedNodeClass::getCallbackStartFunction(void)
874 { return backingNodeClass ? backingNodeClass->getCallbackStartFunction() : VuoCompilerNodeClass::getCallbackStartFunction(); }
875 
876 Function * VuoCompilerSpecializedNodeClass::getCallbackUpdateFunction(void)
877 { return backingNodeClass ? backingNodeClass->getCallbackUpdateFunction() : VuoCompilerNodeClass::getCallbackUpdateFunction(); }
878 
879 Function * VuoCompilerSpecializedNodeClass::getCallbackStopFunction(void)
880 { return backingNodeClass ? backingNodeClass->getCallbackStopFunction() : VuoCompilerNodeClass::getCallbackStopFunction(); }
881 
882 Function * VuoCompilerSpecializedNodeClass::getCompositionAddNodeMetadataFunction(void)
884 
885 Function * VuoCompilerSpecializedNodeClass::getCompositionPerformDataOnlyTransmissionsFunction(void)
887 
888 Function * VuoCompilerSpecializedNodeClass::getCompositionSetPublishedInputPortValueFunction(void)
890 
891 Function * VuoCompilerSpecializedNodeClass::getTriggerWorkerFunction(string portIdentifier)
892 { return backingNodeClass ? backingNodeClass->getTriggerWorkerFunction(portIdentifier) : VuoCompilerNodeClass::getTriggerWorkerFunction(portIdentifier); }
893 
894 vector<VuoCompilerTriggerDescription *> VuoCompilerSpecializedNodeClass::getTriggerDescriptions(void)
895 { return backingNodeClass ? backingNodeClass->getTriggerDescriptions() : VuoCompilerNodeClass::getTriggerDescriptions(); }
896 
897 VuoCompilerInstanceDataClass * VuoCompilerSpecializedNodeClass::getInstanceDataClass(void)
898 { return backingNodeClass ? backingNodeClass->getInstanceDataClass() : VuoCompilerNodeClass::getInstanceDataClass(); }
899 
900 string VuoCompilerSpecializedNodeClass::getDoxygenDocumentation(void)
901 { return backingNodeClass ? backingNodeClass->getDoxygenDocumentation() : VuoCompilerNodeClass::getDoxygenDocumentation(); }
902 
903 string VuoCompilerSpecializedNodeClass::getDefaultSpecializedTypeName(string genericTypeName)
904 { return backingNodeClass ? backingNodeClass->getDefaultSpecializedTypeName(genericTypeName) : VuoCompilerNodeClass::getDefaultSpecializedTypeName(genericTypeName); }
905 
906 vector<string> VuoCompilerSpecializedNodeClass::getAutomaticKeywords(void)
907 { return backingNodeClass ? backingNodeClass->getAutomaticKeywords() : VuoCompilerNodeClass::getAutomaticKeywords(); }
908 
910 { return backingNodeClass ? backingNodeClass->getDependencyName() : VuoCompilerNodeClass::getDependencyName(); }
911 
912 bool VuoCompilerSpecializedNodeClass::isStateful(void)
913 { return backingNodeClass ? backingNodeClass->isStateful() : VuoCompilerNodeClass::isStateful(); }
915 
921 {
922  set<string> deps = (backingNodeClass ? backingNodeClass->getDependencies() : VuoCompilerNodeClass::getDependencies());
923  if (genericNodeClass)
924  deps.insert( genericNodeClass->getBase()->getClassName() );
925  return deps;
926 }