|
@@ -69,6 +69,8 @@ var xml2js = {
|
69
|
69
|
// CLASSES: {
|
70
|
70
|
// <class name>: {
|
71
|
71
|
// description: <class description>,
|
|
72
|
+ // parent: <parent class name>,
|
|
73
|
+ // group: <group name>,
|
72
|
74
|
// methods: { ... },
|
73
|
75
|
// variables: {
|
74
|
76
|
// <variable name>: {
|
|
@@ -83,7 +85,9 @@ var xml2js = {
|
83
|
85
|
// CLASSGROUPS: {
|
84
|
86
|
// <group name>: {
|
85
|
87
|
// description: <group description>,
|
86
|
|
- // classes: [ <class name>, ... ]
|
|
88
|
+ // classes: [ <class name>, ... ],
|
|
89
|
+ // enums: { ... },
|
|
90
|
+ // enums_by_group: { ... }
|
87
|
91
|
// }, ...
|
88
|
92
|
// }
|
89
|
93
|
MODULE: '',
|
|
@@ -98,7 +102,8 @@ var xml2js = {
|
98
|
102
|
TYPEMAPS: {
|
99
|
103
|
'^(const)?\\s*(unsigned|signed)?\\s*(int|short|long|float|double|size_t|u?int\\d{1,2}_t)?$': 'Number',
|
100
|
104
|
'^bool$': 'Boolean',
|
101
|
|
- '^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String' // TODO: verify that swig does this mapping
|
|
105
|
+ '^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String', // TODO: verify that swig does this mapping
|
|
106
|
+ '^void\\s*\\(\\s*\\*\\s*\\)\\s*\\(\\s*void\\s*\\*\\)\\s*$': 'Function'
|
102
|
107
|
},
|
103
|
108
|
|
104
|
109
|
|
|
@@ -157,13 +162,14 @@ var xml2js = {
|
157
|
162
|
try {
|
158
|
163
|
var spec_c = xmlparser.parse(xml)[0];
|
159
|
164
|
var className = getName(spec_c);
|
160
|
|
- xml2js.CLASSES[className] = {
|
|
165
|
+ _.extend(xml2js.CLASSES[className], {
|
161
|
166
|
description: getDescription(spec_c),
|
|
167
|
+ parent: getParent(spec_c, className),
|
162
|
168
|
enums: getEnums(spec_c, false, className),
|
163
|
169
|
enums_by_group: getEnums(spec_c, true, className),
|
164
|
170
|
variables: getVariables(spec_c, className),
|
165
|
171
|
methods: getMethods(spec_c, className)
|
166
|
|
- };
|
|
172
|
+ });
|
167
|
173
|
} catch(e) {
|
168
|
174
|
console.log(e.toString() + ': class ' + className + ' was not parsed correctly.');
|
169
|
175
|
}
|
|
@@ -177,15 +183,48 @@ var xml2js = {
|
177
|
183
|
return fs.readFileAsync(xml2js.opts.inputdir + '/' + fn, 'utf8').then(function(xml) {
|
178
|
184
|
var spec_c = xmlparser.parse(xml)[0];
|
179
|
185
|
if (_.isEmpty(getSubmodules(spec_c))) {
|
180
|
|
- xml2js.CLASSGROUPS[getName(spec_c)] = {
|
|
186
|
+ var group = getName(spec_c);
|
|
187
|
+ var classes = getSubclassNames(spec_c);
|
|
188
|
+ xml2js.CLASSGROUPS[group] = {
|
181
|
189
|
description: getDescription(spec_c),
|
182
|
|
- classes: getSubclassNames(spec_c)
|
183
|
|
- }
|
|
190
|
+ classes: classes
|
|
191
|
+ };
|
|
192
|
+ _.each(classes, function(c) {
|
|
193
|
+ if (_.has(xml2js.CLASSES, c)) {
|
|
194
|
+ xml2js.CLASSES[c].group = group;
|
|
195
|
+ } else {
|
|
196
|
+ console.log('Warning: Group ' + group + ' has unknown class ' + c);
|
|
197
|
+ }
|
|
198
|
+ });
|
184
|
199
|
}
|
185
|
200
|
});
|
186
|
201
|
}));
|
187
|
202
|
});
|
188
|
203
|
return Promise.all(parseClasses.concat(parseGroups));
|
|
204
|
+ }).then(function() {
|
|
205
|
+ if (!_.isEmpty(xml2js.CLASSGROUPS)) {
|
|
206
|
+ // try to categorize ungrouped classes, if any
|
|
207
|
+ var grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
|
|
208
|
+ var ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
|
|
209
|
+ _.each(ungrouped, function(c) {
|
|
210
|
+ _.each(findUsage(c), function(group) {
|
|
211
|
+ xml2js.CLASSGROUPS[group].classes.push(c);
|
|
212
|
+ });
|
|
213
|
+ });
|
|
214
|
+ grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
|
|
215
|
+ ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
|
|
216
|
+ // try to categorize ungrouped enums, if any
|
|
217
|
+ _.each(xml2js.ENUMS_BY_GROUP, function(enumGroupSpec, enumGroupName) {
|
|
218
|
+ _.each(findUsage(enumGroupName, true), function(c) {
|
|
219
|
+ xml2js.CLASSES[c].enums_by_group[enumGroupName] = enumGroupSpec;
|
|
220
|
+ _.each(enumGroupSpec.members, function(enumName) {
|
|
221
|
+ xml2js.CLASSES[c].enums[enumName] = xml2js.ENUMS[enumName];
|
|
222
|
+ delete xml2js.ENUMS[enumName];
|
|
223
|
+ });
|
|
224
|
+ delete xml2js.ENUMS_BY_GROUP[enumGroupName];
|
|
225
|
+ });
|
|
226
|
+ });
|
|
227
|
+ }
|
189
|
228
|
}).then(function() {
|
190
|
229
|
if (xml2js.opts.custom && fs.existsSync(xml2js.opts.custom)) {
|
191
|
230
|
return fs.readFileAsync(xml2js.opts.custom, 'utf8').then(function(custom) {
|
|
@@ -199,9 +238,9 @@ var xml2js = {
|
199
|
238
|
console.log(xml2js.opts.custom ? ('Error: No such customization file exists: ' + xml2js.opts.custom) : 'No customizations given.');
|
200
|
239
|
}
|
201
|
240
|
}).then(function() {
|
|
241
|
+ generateCustomPointerClasses();
|
202
|
242
|
validateMethods();
|
203
|
243
|
validateVars();
|
204
|
|
- generateCustomPointerClasses();
|
205
|
244
|
return _.pick(xml2js, 'MODULE', 'ENUMS', 'ENUMS_BY_GROUP', 'METHODS', 'CLASSES', 'CLASSGROUPS');
|
206
|
245
|
});
|
207
|
246
|
}
|
|
@@ -391,7 +430,30 @@ function generateCustomPointerClasses() {
|
391
|
430
|
}
|
392
|
431
|
|
393
|
432
|
|
394
|
|
-// override autogenerated methods with custom configuration
|
|
433
|
+// search for usage of a type
|
|
434
|
+function findUsage(type, classOnly) {
|
|
435
|
+ var filterClasses = function(fn) { return _.without(_.map(xml2js.CLASSES, fn), undefined); };
|
|
436
|
+ var usesType = function(classSpec, className) {
|
|
437
|
+ var methodsOfType = (_.find(classSpec.methods, function(methodSpec, methodName) {
|
|
438
|
+ return ((!_.isEmpty(methodSpec.return) && methodSpec.return.type == type) ||
|
|
439
|
+ (_.contains(_.pluck(methodSpec.params, 'type'), type)));
|
|
440
|
+ }) != undefined);
|
|
441
|
+ var variablesOfType = _.contains(_.pluck(classSpec.variable, 'type'), type);
|
|
442
|
+ return ((methodsOfType || variablesOfType) ? className : undefined);
|
|
443
|
+ };
|
|
444
|
+ var extendsType = function(classSpec, className) {
|
|
445
|
+ return ((classSpec.parent == type) ? className : undefined);
|
|
446
|
+ };
|
|
447
|
+ var classes = _.union(filterClasses(usesType), filterClasses(extendsType));
|
|
448
|
+ if (classOnly) {
|
|
449
|
+ return classes;
|
|
450
|
+ } else {
|
|
451
|
+ return _.without(_.uniq(_.pluck(_.pick(xml2js.CLASSES, classes), 'group')), undefined);
|
|
452
|
+ }
|
|
453
|
+}
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+// override autogenerated methods with custom configuration
|
395
|
457
|
function customizeMethods(custom) {
|
396
|
458
|
_.each(custom, function(classMethods, className) {
|
397
|
459
|
_.extend(xml2js.CLASSES[className].methods, _.pick(classMethods, function(methodSpec, methodName) {
|
|
@@ -527,6 +589,19 @@ function getSubmodules(spec_c) {
|
527
|
589
|
}
|
528
|
590
|
|
529
|
591
|
|
|
592
|
+// get parent class, if any
|
|
593
|
+function getParent(spec_c, className) {
|
|
594
|
+ var parent = getChild(spec_c, 'basecompoundref');
|
|
595
|
+ if (parent) {
|
|
596
|
+ parent = getText(parent);
|
|
597
|
+ if (!_.has(xml2js.CLASSES, parent)) {
|
|
598
|
+ console.log('WARNING: Class ' + className + ' has unknown parent class ' + parent);
|
|
599
|
+ }
|
|
600
|
+ }
|
|
601
|
+ return parent;
|
|
602
|
+}
|
|
603
|
+
|
|
604
|
+
|
530
|
605
|
function hasParams(paramsSpec) {
|
531
|
606
|
return !(_.isEmpty(paramsSpec) ||
|
532
|
607
|
((_.size(paramsSpec) == 1) && getText(getChild(paramsSpec[0], 'type')) == 'void'));
|
|
@@ -559,6 +634,7 @@ function getMethods(spec_c, parent) {
|
559
|
634
|
if (!_.isEmpty(returnSpec)) {
|
560
|
635
|
retval = getReturn(returnSpec, getReturnDetails(description), methodName, parent);
|
561
|
636
|
}
|
|
637
|
+ methodName = getUniqueMethodName(methodName, spec_js, parent);
|
562
|
638
|
spec_js[methodName] = {
|
563
|
639
|
description: methodDescription,
|
564
|
640
|
params: params,
|
|
@@ -575,6 +651,17 @@ function getMethods(spec_c, parent) {
|
575
|
651
|
}
|
576
|
652
|
|
577
|
653
|
|
|
654
|
+// get a unique string to represent the name of an overloaded method
|
|
655
|
+function getUniqueMethodName(methodName, module, parent) {
|
|
656
|
+ if (methodName in module) {
|
|
657
|
+ do {
|
|
658
|
+ methodName += '!';
|
|
659
|
+ } while (methodName in module);
|
|
660
|
+ }
|
|
661
|
+ return methodName;
|
|
662
|
+}
|
|
663
|
+
|
|
664
|
+
|
578
|
665
|
// get variable specifications for a class
|
579
|
666
|
function getVariables(spec_c, parent) {
|
580
|
667
|
var spec_js = {};
|