Vuo  2.1.0
VuoCompilerMakeListNodeClass.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 
12 #include "VuoGenericType.hh"
13 #include "VuoStringUtilities.hh"
14 
15 #include "VuoCompiler.hh"
24 #include "VuoCompilerPort.hh"
25 #include "VuoNodeClass.hh"
26 #include "VuoPort.hh"
27 
28 
30 const string VuoCompilerMakeListNodeClass::makeListNodeClassNamePrefix = "vuo.list.make.";
31 
33 const string VuoCompilerMakeListNodeClass::makeListNodeClassDescription = "Creates a list from the given items.";
34 
35 
39 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(string nodeClassName, Module *module) :
40  VuoCompilerSpecializedNodeClass(nodeClassName, module)
41 {
42  initialize();
43 }
44 
48 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(VuoCompilerMakeListNodeClass *compilerNodeClass) :
49  VuoCompilerSpecializedNodeClass(compilerNodeClass)
50 {
51  initialize();
52 }
53 
57 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(VuoNodeClass *baseNodeClass) :
58  VuoCompilerSpecializedNodeClass(baseNodeClass)
59 {
60  initialize();
61 }
62 
66 void VuoCompilerMakeListNodeClass::initialize(void)
67 {
68  itemCount = 0;
69  listType = NULL;
70 }
71 
81 VuoNodeClass * VuoCompilerMakeListNodeClass::newNodeClass(string nodeClassName, VuoCompiler *compiler, dispatch_queue_t llvmQueue)
82 {
83  unsigned long itemCount;
84  string itemTypeStr;
85  bool parsedOk = parseNodeClassName(nodeClassName, itemCount, itemTypeStr);
86  if (! parsedOk)
87  return NULL;
88 
89  VuoCompilerType *itemType = compiler->getType(itemTypeStr);
90  VuoCompilerType *listType = compiler->getType(VuoType::listTypeNamePrefix + itemTypeStr);
91  if (! itemType || ! listType)
92  return NULL;
93 
94  __block VuoCompilerMakeListNodeClass *nodeClass;
95 
96  if (! dynamic_cast<VuoGenericType *>(itemType->getBase()))
97  {
98  // The generic port types have been specialized, so generate LLVM bitcode for the node class.
99 
100  dispatch_sync(llvmQueue, ^{
101 
102  Type *itemParamSecondType = NULL;
103  Type *itemParamType = itemType->getFunctionParameterType(&itemParamSecondType);
104  AttributeSet itemParamAttributes = itemType->getFunctionParameterAttributes();
105 
106  Module *module = new Module("", getGlobalContext());
107 
108  // VuoModuleMetadata({});
110 
111 
112  // void nodeEvent
113  // (
114  // VuoInputData(<item type>,<default value>) item1,
115  // ...,
116  // VuoInputData(<item type>,<default value>) item<item count>,
117  // VuoOutputData(VuoList_<item type>) list
118  // )
119 
120  vector<VuoPort *> modelInputPorts;
121  for (unsigned long i = 0; i < itemCount; ++i)
122  {
123  ostringstream oss;
124  oss << i+1;
125  string portName = oss.str();
126 
127  VuoCompilerInputEventPortClass *modelItemPortClass = new VuoCompilerInputEventPortClass(portName, NULL);
128  VuoCompilerInputDataClass *dataClass = new VuoCompilerInputDataClass("", NULL, false);
129  dataClass->setVuoType( itemType->getBase() );
130  modelItemPortClass->setDataClass(dataClass);
131  VuoCompilerPort *modelItemPort = modelItemPortClass->newPort();
132 
133  modelInputPorts.push_back( modelItemPort->getBase() );
134  }
135 
136  VuoCompilerOutputEventPortClass *modelListPortClass = new VuoCompilerOutputEventPortClass("list", NULL);
137  VuoCompilerOutputDataClass *dataClass = new VuoCompilerOutputDataClass("", NULL);
138  dataClass->setVuoType( listType->getBase() );
139  modelListPortClass->setDataClass(dataClass);
140  VuoCompilerPort *modelListPort = modelListPortClass->newPort();
141  vector<VuoPort *> modelOutputPorts( 1, modelListPort->getBase() );
142  map<VuoPort *, size_t> indexOfParameter;
143  map<VuoPort *, size_t> indexOfEventParameter;
144  VuoCompilerConstantStringCache constantStrings;
145 
146  Function *eventFunction = VuoCompilerCodeGenUtilities::getNodeEventFunction(module, "", false, false,
147  nullptr, modelInputPorts, modelOutputPorts,
148  map<VuoPort *, json_object *>(), map<VuoPort *, string>(),
149  map<VuoPort *, string>(), map<VuoPort *, VuoPortClass::EventBlocking>(),
150  indexOfParameter, indexOfEventParameter, constantStrings);
151 
152 
153  // {
154  // *list = VuoListCreate_<item type>();
155  // VuoListAppendValue_<item type>(*list, item1);
156  // ...
157  // VuoListAppendValue_<item type>(*list, item<item count>);
158  // }
159 
160  BasicBlock *block = &(eventFunction->getEntryBlock());
161  PointerType *voidPointerType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
162 
163  string itemBackingTypeName;
164  if (VuoGenericType::isGenericTypeName(itemTypeStr))
165  {
166  itemBackingTypeName = VuoCompilerGenericType::chooseBackingTypeName(itemTypeStr, vector<string>());
167  }
168  else
169  {
170  itemBackingTypeName = itemTypeStr;
171  }
172 
173  string listCreateFunctionName = "VuoListCreate_" + itemBackingTypeName;
174  Function *listCreateFunction = module->getFunction(listCreateFunctionName);
175  if (! listCreateFunction)
176  {
177  vector<Type *> functionParams;
178  FunctionType *functionType = FunctionType::get(voidPointerType, functionParams, false);
179  listCreateFunction = Function::Create(functionType, GlobalValue::ExternalLinkage, listCreateFunctionName, module);
180  }
181 
182  string listAppendFunctionName = "VuoListAppendValue_" + itemBackingTypeName;
183  Function *listAppendFunction = module->getFunction(listAppendFunctionName);
184  if (! listAppendFunction)
185  {
186  vector<Type *> functionParams;
187  functionParams.push_back(voidPointerType);
188  functionParams.push_back(itemParamType);
189  if (itemParamSecondType)
190  {
191  functionParams.push_back(itemParamSecondType);
192  }
193  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
194  listAppendFunction = Function::Create(functionType, GlobalValue::ExternalLinkage, listAppendFunctionName, module);
195 
196  listAppendFunction->setAttributes(VuoCompilerCodeGenUtilities::copyAttributesToIndex(itemParamAttributes, 2));
197  }
198 
199  vector<Value *> itemValues;
200  for (VuoPort *itemPort : modelInputPorts)
201  {
202  size_t argIndex = indexOfParameter[itemPort];
203  Value *itemValue = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, argIndex);
204  itemValues.push_back(itemValue);
205  if (itemParamSecondType)
206  {
207  Value *itemSecondValue = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, argIndex + 1);
208  itemValues.push_back(itemSecondValue);
209  }
210  }
211  size_t listArgIndex = indexOfParameter[modelListPort->getBase()];
212  Value *listVariable = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, listArgIndex);
213 
214  CallInst *listValue = CallInst::Create(listCreateFunction, "", block);
215  Value *listValueAsStruct = VuoCompilerCodeGenUtilities::generateTypeCast(module, block, listValue, static_cast<PointerType *>(listVariable->getType())->getElementType());
216  new StoreInst(listValueAsStruct, listVariable, false, block);
217 
218  for (unsigned long i = 0; i < itemCount; ++i)
219  {
220  int itemValuesIndex = (itemParamSecondType ? 2*i : i);
221  vector<Value *> listAppendParams;
222  listAppendParams.push_back(listValue);
223  listAppendParams.push_back(itemValues[itemValuesIndex]);
224  if (itemParamSecondType)
225  {
226  listAppendParams.push_back(itemValues[itemValuesIndex + 1]);
227  }
228  CallInst *call = CallInst::Create(listAppendFunction, listAppendParams, "", block);
229 
230  call->setAttributes(VuoCompilerCodeGenUtilities::copyAttributesToIndex(itemParamAttributes, 2));
231  }
232 
233  ReturnInst::Create(module->getContext(), block);
234 
235 
236  for (vector<VuoPort *>::iterator i = modelInputPorts.begin(); i != modelInputPorts.end(); ++i)
237  {
238  delete (*i)->getClass()->getCompiler();
239  delete *i;
240  }
241  delete modelListPort;
242  delete modelListPortClass;
243 
244 
245  VuoCompilerMakeListNodeClass *dummyNodeClass = new VuoCompilerMakeListNodeClass(nodeClassName, module);
246 
247  // Reconstruct, this time with a base VuoNodeClass containing actual (non-dummy) ports.
248  nodeClass = new VuoCompilerMakeListNodeClass(dummyNodeClass);
249  delete dummyNodeClass;
250  });
251  }
252  else
253  {
254  // The generic ports have not been specialized, so construct a node class that doesn't yet have an implementation.
255 
256  VuoPortClass *refreshPortClass = (new VuoCompilerInputEventPortClass("refresh"))->getBase();
257 
258  vector<VuoPortClass *> inputPortClasses;
259  inputPortClasses.push_back(refreshPortClass);
260  for (int i = 1; i <= itemCount; ++i)
261  {
262  ostringstream oss;
263  oss << i;
265  VuoCompilerInputDataClass *dataClass = new VuoCompilerInputDataClass("", NULL, false);
266  portClass->setDataClass(dataClass);
267  portClass->setDataVuoType(itemType->getBase());
268  inputPortClasses.push_back(portClass->getBase());
269  }
270 
271  vector<VuoPortClass *> outputPortClasses;
272  {
274  VuoCompilerOutputDataClass *dataClass = new VuoCompilerOutputDataClass("", NULL);
275  portClass->setDataClass(dataClass);
276  portClass->setDataVuoType(listType->getBase());
277  outputPortClasses.push_back(portClass->getBase());
278  }
279 
280  VuoNodeClass *baseNodeClass = new VuoNodeClass(nodeClassName, refreshPortClass, inputPortClasses, outputPortClasses);
281  nodeClass = new VuoCompilerMakeListNodeClass(baseNodeClass);
282  }
283 
284  nodeClass->itemCount = itemCount;
285  nodeClass->listType = listType;
286  nodeClass->specializedForGenericTypeName[ VuoGenericType::createGenericTypeName(1) ] = itemTypeStr;
287 
288  nodeClass->getBase()->setDefaultTitle("Make List");
289  nodeClass->getBase()->setDescription(makeListNodeClassDescription);
290  nodeClass->getBase()->setVersion("2.0.0");
291 
292  return nodeClass->getBase();
293 }
294 
300 {
301  return VuoStringUtilities::beginsWith(nodeClassName, makeListNodeClassNamePrefix);
302 }
303 
308 string VuoCompilerMakeListNodeClass::getNodeClassName(unsigned long itemCount, VuoCompilerType *listType)
309 {
311  return buildNodeClassName(itemCount, itemTypeStr);
312 }
313 
319 bool VuoCompilerMakeListNodeClass::parseNodeClassName(string nodeClassName, unsigned long &itemCount, string &itemTypeName)
320 {
321  string itemCountAndType = VuoStringUtilities::substrAfter(nodeClassName, makeListNodeClassNamePrefix);
322  size_t dotPos = itemCountAndType.find(".");
323  if (dotPos == string::npos || dotPos == 0 || dotPos == itemCountAndType.length() - 1)
324  return false;
325 
326  string itemCountStr = itemCountAndType.substr(0, dotPos);
327  itemCount = atol(itemCountStr.c_str());
328  itemTypeName = itemCountAndType.substr(dotPos + 1);
329  return true;
330 }
331 
335 string VuoCompilerMakeListNodeClass::buildNodeClassName(unsigned long itemCount, string itemTypeName)
336 {
337  ostringstream oss;
338  oss << itemCount;
339  string itemCountStr = oss.str();
340 
341  return makeListNodeClassNamePrefix + itemCountStr + "." + itemTypeName;
342 }
343 
348 {
349  return itemCount;
350 }
351 
356 {
357  return listType;
358 }
359 
364 {
365  if (portClass->getPortType() != VuoPortClass::dataAndEventPort)
366  return NULL;
367 
368  string typeName = VuoGenericType::createGenericTypeName(1);
369  return new VuoGenericType(typeName, vector<string>());
370 }
371 
376 {
377  return "vuo.list.make";
378 }
379 
384 {
385  return makeListNodeClassDescription;
386 }
387 
392 {
394  return NULL;
395 }
396 
400 string VuoCompilerMakeListNodeClass::createUnspecializedNodeClassName(set<VuoPortClass *> portClassesToUnspecialize)
401 {
402  bool foundDataAndEvent = false;
403  for (set<VuoPortClass *>::iterator i = portClassesToUnspecialize.begin(); i != portClassesToUnspecialize.end(); ++i)
404  if ((*i)->getPortType() == VuoPortClass::dataAndEventPort)
405  foundDataAndEvent = true;
406 
407  if (! foundDataAndEvent)
408  return getBase()->getClassName();
409 
411 }
412 
417 string VuoCompilerMakeListNodeClass::createSpecializedNodeClassNameWithReplacement(string genericTypeName, string specializedTypeName)
418 {
419  unsigned long itemCount = 0;
420  string itemTypeName;
421  parseNodeClassName(getBase()->getClassName(), itemCount, itemTypeName);
422 
423  string specializedItemTypeName = (itemTypeName == genericTypeName ? specializedTypeName : itemTypeName);
424  return buildNodeClassName(itemCount, specializedItemTypeName);
425 }