1 /*
2  * Copyright(C) 2006 Bill Cox
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  *(at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
17  */
18 
19 #include "dv.h"
20 
21 /*--------------------------------------------------------------------------------------------------
22   Create new classes that are just useful for holding dynamic arrays of objects.
23 --------------------------------------------------------------------------------------------------*/
createClassDynamicArrayClasses(dvModule module)24 static void createClassDynamicArrayClasses(
25     dvModule module)
26 {
27     dvClass theClass, dynarrayClass;
28     dvClass lastClass = dvModuleGetLastClass(module);
29     dvRelationship rel;
30     utSym sym;
31 
32     dvForeachModuleClass(module, theClass) {
33         if(dvClassGenerateArrayClass(theClass)) {
34             sym = utSymCreateFormatted("%sArray", utCopyString(dvClassGetName(theClass)));
35             dynarrayClass = dvClassCreate(module, sym, dvClassNull);
36             rel = dvRelationshipCreate(dvSchemaNull, dynarrayClass, theClass, REL_ARRAY, utSymNull, utSymNull);
37             dvRelationshipSetAccessParent(rel, false);
38         }
39         if(theClass == lastClass) {
40             return; /* Don't build array classes for themselves! */
41         }
42     } dvEndModuleClass;
43 }
44 
45 /*--------------------------------------------------------------------------------------------------
46   Create the attribute class.
47 --------------------------------------------------------------------------------------------------*/
createAttributeClass(dvModule module,dvEnum attributeTypeEnum)48 static dvClass createAttributeClass(
49     dvModule module,
50     dvEnum attributeTypeEnum)
51 {
52     dvClass attributeClass = dvClassCreate(module, utSymCreate("Attribute"), dvClassNull);
53     utSym typeSym = utSymCreate("Type");
54     dvProperty typeProp = dvPropertyCreate(attributeClass, dvUnionNull, PROP_ENUM, typeSym);
55     dvUnion valueUnion = dvUnionCreate(attributeClass, typeSym, 1);
56     dvProperty int64Prop, doubleProp, boolProp, symProp;
57     dvProperty dataProp;
58 
59     dvPropertySetEnumProp(typeProp, attributeTypeEnum);
60     dvUnionSetTypeProperty(valueUnion, typeProp);
61     int64Prop = dvPropertyCreate(attributeClass, valueUnion, PROP_INT, utSymCreate("Int64Val"));
62     dvPropertySetWidth(int64Prop, 64);
63     doubleProp = dvPropertyCreate(attributeClass, valueUnion, PROP_DOUBLE, utSymCreate("DoubleVal"));
64     boolProp = dvPropertyCreate(attributeClass, valueUnion, PROP_BOOL, utSymCreate("BoolVal"));
65     symProp = dvPropertyCreate(attributeClass, valueUnion, PROP_SYM, utSymCreate("SymVal"));
66     dvCaseCreate(int64Prop, dvEnumFindEntry(attributeTypeEnum, utSymCreate("INT64")));
67     dvCaseCreate(doubleProp, dvEnumFindEntry(attributeTypeEnum, utSymCreate("DOUBLE")));
68     dvCaseCreate(boolProp, dvEnumFindEntry(attributeTypeEnum, utSymCreate("BOOL")));
69     dvCaseCreate(symProp, dvEnumFindEntry(attributeTypeEnum, utSymCreate("SYM")));
70     dataProp = dvPropertyCreate(attributeClass, dvUnionNull, PROP_UINT, utSymCreate("Data"));
71     dvPropertySetWidth(dataProp, 8);
72     dvPropertySetArray(dataProp, true);
73     return attributeClass;
74 }
75 
76 /*--------------------------------------------------------------------------------------------------
77   Create local Attrlist and Attribute classes, with a hash table between them, and put a cascade
78   pointer from each class with attributes to Attrlist.
79 --------------------------------------------------------------------------------------------------*/
createClassAttributesWithAttributeTypeEnum(dvModule module,dvEnum attributeTypeEnum)80 static void createClassAttributesWithAttributeTypeEnum(
81     dvModule module,
82     dvEnum attributeTypeEnum)
83 {
84     utSym attrlistSym = utSymCreate("Attrlist");
85     dvClass attrlistClass = dvClassCreate(module, attrlistSym, dvClassNull);
86     dvClass attributeClass = createAttributeClass(module, attributeTypeEnum);
87     dvRelationship hashRel = dvRelationshipCreate(dvSchemaNull, attrlistClass, attributeClass, REL_HASHED, utSymNull,
88         utSymNull);
89     dvRelationship relationship;
90     dvClass theClass;
91 
92     dvAddDefaultKey(hashRel);
93     dvRelationshipSetMandatory(hashRel, true);
94     dvForeachModuleClass(module, theClass) {
95         if(dvClassGenerateAttributes(theClass)) {
96             relationship = dvRelationshipCreate(dvSchemaNull, theClass, attrlistClass, REL_POINTER, utSymNull, utSymNull);
97             dvRelationshipSetAccessParent(relationship, false);
98             dvRelationshipSetCascade(relationship, true);
99             dvRelationshipSetSparse(relationship, true);
100         }
101     } dvEndModuleClass;
102 }
103 
104 /*--------------------------------------------------------------------------------------------------
105   Create local Attrlist and Attribute classes, with a hash table between them, and put a cascade
106   pointer from each class with attributes to Attrlist.
107 --------------------------------------------------------------------------------------------------*/
createClassAttributes(dvModule module)108 static void createClassAttributes(
109     dvModule module)
110 {
111     utSym sym = utSymCreate("AttributeType");
112     utSym prefix = utSymCreateFormatted("%s_ATTR", utStringToUpperCase(dvModuleGetPrefix(module)));
113     dvEnum attributeTypeEnum = dvEnumCreate(module, sym, prefix);
114 
115     dvEntryCreate(attributeTypeEnum, utSymCreate("INT64"), 0);
116     dvEntryCreate(attributeTypeEnum, utSymCreate("DOUBLE"), 1);
117     dvEntryCreate(attributeTypeEnum, utSymCreate("BOOL"), 2);
118     dvEntryCreate(attributeTypeEnum, utSymCreate("SYM"), 3);
119     dvEntryCreate(attributeTypeEnum, utSymCreate("STRING"), 4);
120     dvEntryCreate(attributeTypeEnum, utSymCreate("BLOB"), 5);
121     createClassAttributesWithAttributeTypeEnum(module, attributeTypeEnum);
122 }
123 
124 /*--------------------------------------------------------------------------------------------------
125   Create the property, and copy the sparse field from the relationship to it.
126 --------------------------------------------------------------------------------------------------*/
relPropertyCreate(dvClass theClass,dvRelationship relationship,dvPropertyType type,utSym sym)127 static dvProperty relPropertyCreate(
128     dvClass theClass,
129     dvRelationship relationship,
130     dvPropertyType type,
131     utSym sym)
132 {
133     dvProperty property = dvPropertyCreate(theClass, dvUnionNull, type, sym);
134 
135     dvRelationshipAppendProperty(relationship, property);
136     dvPropertySetSparse(property, dvRelationshipSparse(relationship));
137     return property;
138 }
139 
140 /*--------------------------------------------------------------------------------------------------
141   Create fields used by the relationship.  Note that we copy the label strings because we are
142   creating new symbols in this fuction, which could cause them to move in memory.
143 --------------------------------------------------------------------------------------------------*/
generateRelationshipFields(dvRelationship relationship)144 static void generateRelationshipFields(
145     dvRelationship relationship)
146 {
147     dvClass parent = dvRelationshipGetParentClass(relationship);
148     dvClass child = dvRelationshipGetChildClass(relationship);
149     dvProperty prop;
150     utSym sym;
151     char *parentName = utCopyString(dvClassGetName(parent));
152     char *childName = utCopyString(dvClassGetName(child));
153     char *parentLabel = utCopyString(dvRelationshipGetParentLabel(relationship));
154     char *childLabel = utCopyString(dvRelationshipGetChildLabel(relationship));
155     dvRelationshipType type = dvRelationshipGetType(relationship);
156 
157     if(dvRelationshipAccessParent(relationship)) {
158         /* Owner pointer */
159         sym = utSymCreateFormatted("%s%s", parentLabel, parentName);
160         prop = dvClassFindProperty(child, sym);
161         if(prop != dvPropertyNull) {
162             if(dvPropertyGetClass(prop) != child ||
163                     dvPropertyGetUnion(prop) != dvUnionNull ||
164                     dvPropertyGetType(prop) != PROP_POINTER) {
165                 utExit("Property %s defined differently the second time", utSymGetName(sym));
166             }
167             /* Must be a duplicated relationship */
168             dvRelationshipSetSharedParent(relationship, true);
169         } else {
170             prop = relPropertyCreate(child, relationship, PROP_POINTER, sym);
171             dvPropertySetClassProp(prop, parent);
172         }
173     }
174     if(!dvRelationshipAccessChild(relationship)) {
175         return;
176     }
177     if(type == REL_POINTER) {
178         /* Child pointer */
179         sym = utSymCreateFormatted("%s%s", childLabel, childName);
180         prop = relPropertyCreate(parent, relationship, PROP_POINTER, sym);
181         dvPropertySetClassProp(prop, child);
182     }
183     if(type == REL_LINKED_LIST || type == REL_TAIL_LINKED || type == REL_DOUBLY_LINKED ||
184             type == REL_HASHED) {
185         /* First pointer */
186         sym = utSymCreateFormatted("First%s%s", childLabel, childName);
187         prop = relPropertyCreate(parent, relationship, PROP_POINTER, sym);
188         dvPropertySetClassProp(prop, child);
189         /* Next child pointer */
190         sym = utSymCreateFormatted("Next%s%s%s", parentName, childLabel, childName);
191         prop = relPropertyCreate(child, relationship, PROP_POINTER, sym);
192         dvPropertySetClassProp(prop, child);
193     }
194     if(type == REL_TAIL_LINKED || type == REL_DOUBLY_LINKED || type == REL_HASHED) {
195         /* Last pointer */
196         sym = utSymCreateFormatted("Last%s%s", childLabel, childName);
197         prop = relPropertyCreate(parent, relationship, PROP_POINTER, sym);
198         dvPropertySetClassProp(prop, child);
199     }
200     if(type == REL_DOUBLY_LINKED || type == REL_HASHED) {
201         /* Previous child pointer */
202         sym = utSymCreateFormatted("Prev%s%s%s", parentName, childLabel, childName);
203         prop = relPropertyCreate(child, relationship, PROP_POINTER, sym);
204         dvPropertySetClassProp(prop, child);
205     }
206     if(type == REL_ARRAY || type == REL_HEAP) {
207         /* Array of children */
208         sym = utSymCreateFormatted("%s%s", childLabel, childName);
209         prop = relPropertyCreate(parent, relationship, PROP_POINTER, sym);
210         dvPropertySetClassProp(prop, child);
211         dvPropertySetArray(prop, true);
212         if(dvRelationshipAccessParent(relationship)) {
213             /* Index on parent */
214             sym = utSymCreateFormatted("%s%sIndex", parentName, childLabel);
215             prop = relPropertyCreate(child, relationship, PROP_UINT, sym);
216             dvPropertySetWidth(prop, 32);
217         }
218         /* Used children on parent */
219         sym = utSymCreateFormatted("Used%s%s", childLabel, childName);
220         prop = relPropertyCreate(parent, relationship, PROP_UINT, sym);
221         dvPropertySetWidth(prop, 32);
222     }
223     if(type == REL_HASHED) {
224         /* Hash table */
225         sym = utSymCreateFormatted("%s%sTable", childLabel, childName);
226         prop = relPropertyCreate(parent, relationship, PROP_POINTER, sym);
227         dvPropertySetClassProp(prop, child);
228         dvPropertySetArray(prop, true);
229         /* Number of entries in table */
230         sym = utSymCreateFormatted("Num%s%s", childLabel, childName);
231         prop = relPropertyCreate(parent, relationship, PROP_UINT, sym);
232         dvPropertySetWidth(prop, 32);
233         /* Next child in table */
234         sym = utSymCreateFormatted("NextTable%s%s%s", parentName, childLabel, childName);
235         prop = relPropertyCreate(child, relationship, PROP_POINTER, sym);
236         dvPropertySetClassProp(prop, child);
237     }
238 }
239 
240 /*--------------------------------------------------------------------------------------------------
241   Create all the module's fields used by relationships.
242 --------------------------------------------------------------------------------------------------*/
createModuleRelationshipFields(dvModule module)243 static void createModuleRelationshipFields(
244     dvModule module)
245 {
246     dvRelationship relationship;
247     dvClass theClass;
248 
249     dvForeachModuleClass(module, theClass) {
250         dvForeachClassChildRelationship(theClass, relationship) {
251             if(!dvRelationshipExpanded(relationship)) {
252                 dvRelationshipSetExpanded(relationship, true);
253                 generateRelationshipFields(relationship);
254             }
255         } dvEndClassChildRelationship;
256     } dvEndModuleClass;
257 }
258 
259 /*--------------------------------------------------------------------------------------------------
260   Build sparsegroups for sparse classes.
261 --------------------------------------------------------------------------------------------------*/
buildClassExtensionSparsegroups(dvModule module)262 static void buildClassExtensionSparsegroups(
263     dvModule module)
264 {
265     dvClass theClass;
266     dvSparsegroup sparsegroup;
267     dvProperty property;
268     utSym sym;
269 
270     dvForeachModuleClass(module, theClass) {
271         if(dvClassSparse(theClass)) {
272             sym = utSymCreateFormatted("Sparse%sData", dvClassGetName(theClass));
273             sparsegroup = dvSparsegroupCreate(theClass, sym);
274             dvForeachClassProperty(theClass, property) {
275                 if(dvPropertyGetUnion(property) == dvUnionNull && !dvPropertyArray(property)) {
276                     dvSparsegroupAppendProperty(sparsegroup, property);
277                     dvPropertySetSparse(property, true);
278                 }
279             } dvEndClassProperty;
280         }
281     } dvEndModuleClass;
282 }
283 
284 /*--------------------------------------------------------------------------------------------------
285   Build sparsegroups for sparse relationships.
286 --------------------------------------------------------------------------------------------------*/
buildRelationshipSparsegroups(dvModule module)287 static void buildRelationshipSparsegroups(
288     dvModule module)
289 {
290     dvClass parent, child;
291     dvRelationship relationship;
292     dvSparsegroup sparsegroup;
293     dvProperty property;
294     utSym sym;
295 
296     dvForeachModuleClass(module, parent) {
297         dvForeachClassChildRelationship(parent, relationship) {
298             if(dvRelationshipSparse(relationship)) {
299                 child = dvRelationshipGetChildClass(relationship);
300                 sym = utSymCreateFormatted("SparseParent%s%s%sData", dvRelationshipGetParentLabel(relationship),
301                     dvClassGetName(parent), dvClassGetName(child));
302                 sparsegroup = dvSparsegroupCreate(parent, sym);
303                 dvRelationshipSetParentSparsegroup(relationship, sparsegroup);
304                 dvSparsegroupSetRelationship(sparsegroup, relationship);
305                 sym = utSymCreateFormatted("SparseChild%s%s%sData",  dvClassGetName(parent),
306                     dvRelationshipGetChildLabel(relationship), dvClassGetName(child));
307                 sparsegroup = dvSparsegroupCreate(child, sym);
308                 dvRelationshipSetChildSparsegroup(relationship, sparsegroup);
309                 dvSparsegroupSetRelationship(sparsegroup, relationship);
310                 dvForeachRelationshipProperty(relationship, property) {
311                     if(dvPropertyGetSparsegroup(property) == dvSparsegroupNull && !dvPropertyArray(property)) {
312                         if(dvPropertyGetClass(property) == parent) {
313                             dvSparsegroupAppendProperty(dvRelationshipGetParentSparsegroup(relationship), property);
314                             dvPropertySetSparse(property, true);
315                         } else {
316                             dvSparsegroupAppendProperty(dvRelationshipGetChildSparsegroup(relationship), property);
317                             dvPropertySetSparse(property, true);
318                         }
319                     }
320                 } dvEndRelationshipProperty;
321             }
322         } dvEndClassChildRelationship;
323     } dvEndModuleClass;
324 }
325 
326 /*--------------------------------------------------------------------------------------------------
327   Build sparsegroups for sparse array properties.
328 --------------------------------------------------------------------------------------------------*/
buildArraySparsegroups(dvModule module)329 static void buildArraySparsegroups(
330     dvModule module)
331 {
332     dvClass theClass;
333     dvSparsegroup sparsegroup;
334     dvProperty property, firstProp, numProp;
335     utSym sym;
336 
337     dvForeachModuleClass(module, theClass) {
338         dvForeachClassProperty(theClass, property) {
339             if(dvPropertyArray(property) && !dvPropertyFixedSize(property)) {
340                 firstProp = dvPropertyGetFirstElementProp(property);
341                 numProp = dvPropertyGetNumElementsProp(property);
342                 if(dvPropertySparse(firstProp) && dvPropertyGetSparsegroup(firstProp) == dvSparsegroupNull) {
343                     sym = utSymCreateFormatted("Sparse%s%sData",  dvClassGetName(theClass),
344                         dvPropertyGetName(property));
345                     sparsegroup = dvSparsegroupCreate(theClass, sym);
346                     dvSparsegroupAppendProperty(sparsegroup, firstProp);
347                     dvSparsegroupAppendProperty(sparsegroup, numProp);
348                 }
349             }
350         } dvEndClassProperty;
351     } dvEndModuleClass;
352 }
353 
354 /*--------------------------------------------------------------------------------------------------
355   Build sparsegroups for any remaining sparse properties.
356 --------------------------------------------------------------------------------------------------*/
buildPropertySparsegroups(dvModule module)357 static void buildPropertySparsegroups(
358     dvModule module)
359 {
360     dvClass theClass;
361     dvSparsegroup sparsegroup;
362     dvProperty property;
363     utSym sym;
364 
365     dvForeachModuleClass(module, theClass) {
366         dvForeachClassProperty(theClass, property) {
367             if(dvPropertySparse(property) && dvPropertyGetSparsegroup(property) == dvSparsegroupNull) {
368                 sym = utSymCreateFormatted("Sparse%s%sData",  dvClassGetName(theClass),
369                     dvPropertyGetName(property));
370                 sparsegroup = dvSparsegroupCreate(theClass, sym);
371                 dvSparsegroupAppendProperty(sparsegroup, property);
372             }
373         } dvEndClassProperty;
374     } dvEndModuleClass;
375 }
376 
377 /*--------------------------------------------------------------------------------------------------
378   Build sparsegroups, which represent groups of related properties in a class that should be kept
379   together in a single sparse data hash table.
380 --------------------------------------------------------------------------------------------------*/
buildSparsegroups(dvModule module)381 static void buildSparsegroups(
382     dvModule module)
383 {
384     buildClassExtensionSparsegroups(module);
385     buildRelationshipSparsegroups(module);
386     buildArraySparsegroups(module);
387     buildPropertySparsegroups(module);
388 }
389 
390 /*--------------------------------------------------------------------------------------------------
391   Create the DatadrawRoot class to keep track  of sparse data.
392 --------------------------------------------------------------------------------------------------*/
createGlobalRoot(dvModule module)393 static dvClass createGlobalRoot(
394     dvModule module)
395 {
396     dvClass datadrawRoot = dvClassCreate(module, utSymCreate("DatadrawRoot"), dvClassNull);
397 
398     dvClassSetMemoryStyle(datadrawRoot, MEM_CREATE_ONLY);
399     return datadrawRoot;
400 }
401 
402 /*--------------------------------------------------------------------------------------------------
403   Copy the property to the sparse data class.
404 --------------------------------------------------------------------------------------------------*/
addSparseDataProperty(dvClass dataClass,dvProperty property)405 static void addSparseDataProperty(
406     dvClass dataClass,
407     dvProperty property)
408 {
409     dvProperty valueProperty = dvPropertyCreate(dataClass, dvUnionNull, dvPropertyGetType(property),
410         dvPropertyGetSym(property));
411 
412     dvPropertyCopyProps(property, valueProperty);
413     dvPropertySetSparse(valueProperty, false);
414     switch(dvPropertyGetType(property)) {
415     case PROP_ENUM:
416         dvPropertySetEnumProp(valueProperty, dvPropertyGetEnumProp(property));
417         break;
418     case PROP_TYPEDEF:
419         dvPropertySetTypedefProp(valueProperty, dvPropertyGetTypedefProp(property));
420         break;
421     case PROP_POINTER:
422         dvPropertySetClassProp(valueProperty, dvPropertyGetClassProp(property));
423         break;
424     case PROP_SYM:
425         dvPropertySetTypeSym(valueProperty, dvPropertyGetTypeSym(property));
426         break;
427     case PROP_INT: case PROP_UINT:
428         dvPropertySetWidth(valueProperty, dvPropertyGetWidth(property));
429         break;
430     default:
431         /* Nothing needed */
432         break;
433     }
434 }
435 
436 /*--------------------------------------------------------------------------------------------------
437   Create a class to hold the sparsegroup's property data, and create a hashed relationship from
438   the root to it.
439 --------------------------------------------------------------------------------------------------*/
createSparsegroupClass(dvSparsegroup sparsegroup,dvClass datadrawRoot)440 static void createSparsegroupClass(
441     dvSparsegroup sparsegroup,
442     dvClass datadrawRoot)
443 {
444     dvClass theClass = dvSparsegroupGetClass(sparsegroup);
445     dvModule module = dvClassGetModule(theClass);
446     dvClass dataClass = dvClassCreate(module, dvSparsegroupGetSym(sparsegroup), dvClassNull);
447     dvRelationship relationship = dvRelationshipCreate(dvSchemaNull, datadrawRoot, dataClass, REL_HASHED, utSymNull,
448         utSymNull);
449     utSym sym = utSymCreateFormatted("%sKey", dvClassGetName(theClass));
450     dvProperty objectProperty = dvPropertyCreate(dataClass, dvUnionNull, PROP_POINTER, sym);
451     dvProperty property;
452 
453     dvPropertySetClassProp(objectProperty, theClass);
454     dvKeyCreate(relationship, objectProperty);
455     dvForeachSparsegroupProperty(sparsegroup, property) {
456         addSparseDataProperty(dataClass, property);
457     } dvEndSparsegroupProperty;
458     dvRelationshipSetAccessParent(relationship, false);
459 }
460 
461 /*--------------------------------------------------------------------------------------------------
462   Create sparse data helper classes.
463 --------------------------------------------------------------------------------------------------*/
createSparseDataClasses(dvModule module)464 static void createSparseDataClasses(
465     dvModule module)
466 {
467     dvClass theClass;
468     dvClass datadrawRoot = dvClassNull;
469     dvSparsegroup sparsegroup;
470     bool firstTime = true;
471 
472     dvForeachModuleClass(module, theClass) {
473         dvForeachClassSparsegroup(theClass, sparsegroup) {
474             if(dvSparsegroupGetFirstProperty(sparsegroup) != dvPropertyNull) {
475                 /* We wait to deal with arrays until after their fields are generated */
476                 if(firstTime) {
477                     dvModuleSetHasSparseData(module, true);
478                     datadrawRoot = createGlobalRoot(module);
479                     firstTime = false;
480                 }
481                 createSparsegroupClass(sparsegroup, datadrawRoot);
482             }
483         } dvEndClassSparsegroup;
484     } dvEndModuleClass;
485 }
486 
487 /*--------------------------------------------------------------------------------------------------
488   Bind keys to the properties they refer to.
489 --------------------------------------------------------------------------------------------------*/
bindKeysToProperties(dvModule module)490 static void bindKeysToProperties(
491     dvModule module)
492 {
493     dvClass theClass;
494     dvRelationship relationship;
495     dvProperty property;
496     dvKey key;
497 
498     dvForeachModuleClass(module, theClass) {
499         dvForeachClassParentRelationship(theClass, relationship) {
500             if(dvRelationshipGetType(relationship) == REL_HASHED) {
501                 dvForeachRelationshipKey(relationship, key) {
502                     if(dvKeyGetProperty(key) == dvPropertyNull) {
503                         property = dvClassFindProperty(theClass, dvKeyGetPropertySym(key));
504                         if(property == dvPropertyNull) {
505                             utExit("Line %u: key %s not found on class %s", dvKeyGetLineNum(key),
506                                 utSymGetName(dvKeyGetPropertySym(key)), dvClassGetName(theClass));
507                         }
508                         dvPropertyAppendKey(property, key);
509                     }
510                 } dvEndRelationshipKey;
511             }
512         } dvEndClassParentRelationship;
513     } dvEndModuleClass;
514 }
515 
516 /*--------------------------------------------------------------------------------------------------
517   Move the new property in front of the old property in the list of properties on a class.
518 --------------------------------------------------------------------------------------------------*/
movePropInFront(dvProperty newProp,dvProperty oldProp)519 static void movePropInFront(
520     dvProperty newProp,
521     dvProperty oldProp)
522 {
523     dvClass theClass = dvPropertyGetClass(newProp);
524 
525     dvClassRemoveProperty(theClass, newProp);
526     if(dvClassGetFirstProperty(theClass) == oldProp) {
527         dvClassInsertProperty(theClass, newProp);
528     } else {
529         dvClassInsertAfterProperty(theClass, dvPropertyGetPrevClassProperty(oldProp), newProp);
530     }
531 }
532 
533 /*--------------------------------------------------------------------------------------------------
534   Generate array fields.  Move them in front of their array properties so when we read them from
535   a backup file, they already have been defined.
536 --------------------------------------------------------------------------------------------------*/
createArrayFields(dvModule module)537 static void createArrayFields(
538     dvModule module)
539 {
540     dvClass theClass;
541     dvProperty property, newProp;
542     utSym sym;
543 
544     dvForeachModuleClass(module, theClass) {
545         dvForeachClassProperty(theClass, property) {
546             if(dvPropertyArray(property) && !dvPropertyExpanded(property) && !dvPropertyFixedSize(property)) {
547                 dvPropertySetExpanded(property, true);
548                 /* Index into heap for first element */
549                 sym = utSymCreateFormatted("%sIndex", utCopyString(dvPropertyGetName(property)));
550                 newProp = dvPropertyCreate(theClass, dvUnionNull, PROP_UINT, sym);
551                 dvPropertySetWidth(newProp, 32);
552                 dvPropertySetFirstElementProp(property, newProp);
553                 movePropInFront(newProp, property);
554                 dvPropertySetHidden(newProp, true);
555                 dvPropertySetSparse(newProp, dvPropertySparse(property));
556                 if(dvPropertyGetRelationship(property) != dvRelationshipNull) {
557                     dvRelationshipAppendProperty(dvPropertyGetRelationship(property), newProp);
558                 }
559                 /* Number of elements allocated in array */
560                 sym = utSymCreateFormatted("Num%s", utCopyString(dvPropertyGetName(property)));
561                 newProp = dvPropertyCreate(theClass, dvUnionNull, PROP_UINT, sym);
562                 dvPropertySetWidth(newProp, 32);
563                 dvPropertySetNumElementsProp(property, newProp);
564                 movePropInFront(newProp, property);
565                 dvPropertySetHidden(newProp, true);
566                 dvPropertySetSparse(newProp, dvPropertySparse(property));
567                 dvPropertySetSparse(property, false);
568                 if(dvPropertyGetRelationship(property) != dvRelationshipNull) {
569                     dvRelationshipAppendProperty(dvPropertyGetRelationship(property), newProp);
570                 }
571             }
572         } dvEndClassProperty;
573     } dvEndModuleClass;
574 }
575 
576 /*--------------------------------------------------------------------------------------------------
577   Find the size of a property element in bits.  For typedef properties, we return 0.
578 --------------------------------------------------------------------------------------------------*/
dvFindPropertySize(dvProperty property)579 uint8 dvFindPropertySize(
580     dvProperty property)
581 {
582     switch(dvPropertyGetType(property)) {
583     case PROP_INT:
584     case PROP_UINT:
585         return dvPropertyGetWidth(property);
586     case PROP_FLOAT:
587         return sizeof(float) << 3;
588     case PROP_DOUBLE:
589         return sizeof(double) << 3;
590     case PROP_BOOL:
591         return sizeof(bool) << 3;
592     case PROP_CHAR:
593         return sizeof(char) << 3;
594     case PROP_ENUM:
595         return sizeof(int) << 3;
596     case PROP_TYPEDEF:
597         return 0; /* We don't really know */
598     case PROP_POINTER:
599         return dvClassGetReferenceSize(dvPropertyGetClassProp(property));
600     case PROP_SYM:
601         return sizeof(utSym) << 3;
602     case PROP_BIT:
603         return 1;
604     default:
605         utExit("Unknown property type");
606     }
607     return 0; /* Dummy return */
608 }
609 
610 /*--------------------------------------------------------------------------------------------------
611   Find a field on the class for use as a next pointer on a free list.  With DD_DEBUG set,
612   references are either 32-bit or 64-bit, depending on if we are on a 64-bit machine.  So, only
613   use reference fields for next pointers, not data.
614 --------------------------------------------------------------------------------------------------*/
findFieldForNextFreePointer(dvClass theClass)615 static dvProperty findFieldForNextFreePointer(
616     dvClass theClass)
617 {
618     dvProperty property;
619     dvPropertyType type;
620     uint32 refSize = dvClassGetReferenceSize(theClass);
621 
622     dvForeachClassProperty(theClass, property) {
623         type = dvPropertyGetType(property);
624         if((type == PROP_POINTER || type == PROP_SYM) && !dvPropertyArray(property) && !dvPropertySparse(property) &&
625                 (dvFindPropertySize(property) == refSize && dvPropertyGetUnion(property) == dvUnionNull)) {
626             return property;
627         }
628     } dvEndClassProperty;
629     return dvPropertyNull;
630 }
631 
632 /*--------------------------------------------------------------------------------------------------
633   Find a field on the class large enough to hold the next pointer.  If none exist, allocate it.
634 --------------------------------------------------------------------------------------------------*/
setFreeListFields(dvModule module)635 static void setFreeListFields(
636     dvModule module)
637 {
638     dvClass theClass;
639     dvProperty property;
640     utSym sym;
641 
642     dvForeachModuleClass(module, theClass) {
643         if(dvClassGetBaseClass(theClass) == dvClassNull && dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) {
644             property = findFieldForNextFreePointer(theClass);
645             if(property == dvPropertyNull) {
646                 sym = utSymCreate("FreeList");
647                 property = dvPropertyCreate(theClass, dvUnionNull, PROP_POINTER, sym);
648                 dvPropertySetClassProp(property, theClass);
649                 dvPropertySetHidden(property, true);
650             }
651             dvClassSetFreeListProperty(theClass, property);
652         }
653     } dvEndModuleClass;
654 }
655 
656 /*--------------------------------------------------------------------------------------------------
657   Just count the number fields that we will need to track.  Set the total number of fields on
658   dvTheRoot.
659 --------------------------------------------------------------------------------------------------*/
setPropertyFieldNumbers(dvModule module)660 static void setPropertyFieldNumbers(
661     dvModule module)
662 {
663     dvClass theClass;
664     dvUnion theUnion;
665     dvCase theCase;
666     dvEnum theEnum;
667     dvEntry entry;
668     dvProperty property;
669     uint16 classNumber = 0;
670     uint16 fieldNumber = 0;
671     uint16 enumNumber = 0;
672     uint16 entryNumber;
673     uint16 unionCaseNumber;
674     uint16 xField;
675 
676     dvForeachModuleClass(module, theClass) {
677         xField = 0;
678         dvForeachClassProperty(theClass, property) {
679             if(dvPropertyGetUnion(property) == dvUnionNull && !dvPropertySparse(property)) {
680                 dvPropertySetFieldNumber(property, fieldNumber);
681                 fieldNumber++;
682                 xField++;
683             }
684         } dvEndClassProperty;
685         dvForeachClassUnion(theClass, theUnion) {
686             dvUnionSetFieldNumber(theUnion, fieldNumber);
687             unionCaseNumber = 0;
688             dvForeachUnionProperty(theUnion, property) {
689                 dvForeachPropertyCase(property, theCase) {
690                     unionCaseNumber++;
691                 } dvEndPropertyCase;
692             } dvEndUnionProperty;
693             dvUnionSetNumCases(theUnion, unionCaseNumber);
694             fieldNumber++;
695             xField++;
696         } dvEndClassUnion;
697         dvClassSetNumFields(theClass, xField);
698         dvClassSetNumber(theClass, classNumber);
699         classNumber++;
700     } dvEndModuleClass;
701     dvModuleSetNumFields(module, fieldNumber);
702     dvModuleSetNumClasses(module, classNumber);
703     dvForeachModuleEnum(module, theEnum) {
704         enumNumber++;
705         entryNumber = 0;
706         dvForeachEnumEntry(theEnum, entry) {
707             entryNumber++;
708         } dvEndEnumEntry;
709         dvEnumSetNumEntries(theEnum, entryNumber);
710     } dvEndModuleEnum;
711     dvModuleSetNumEnums(module, enumNumber);
712 }
713 
714 /*--------------------------------------------------------------------------------------------------
715   Generate code from the file.
716 --------------------------------------------------------------------------------------------------*/
dvGenerateCode(dvModule module,char * includeFile,char * sourceFile)717 bool dvGenerateCode(
718     dvModule module,
719     char *includeFile,
720     char *sourceFile)
721 {
722     createClassDynamicArrayClasses(module);
723     if(dvModuleHasClassAttributes(module)) {
724         createClassAttributes(module);
725     }
726     createModuleRelationshipFields(module);
727     createArrayFields(module);
728     /* Since this creates new relationships, we have to generate relationship and array fields again.
729        We set an "Expanded" flag on relationships and array properties that have already been processed */
730     buildSparsegroups(module);
731     createSparseDataClasses(module);
732     createModuleRelationshipFields(module);
733     createArrayFields(module);
734     bindKeysToProperties(module); /* Wait until here, so we can use generated fields for hash keys */
735     setFreeListFields(module);
736     setPropertyFieldNumbers(module);
737     dvWriteHeaderFile(module, includeFile);
738     dvWriteCFile(module, sourceFile);
739     return true;
740 }
741