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