1765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/*
2765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Author: Heidi Pan <heidi.pan@intel.com>
3765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Copyright (c) 2015 Intel Corporation.
4765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
5765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Permission is hereby granted, free of charge, to any person obtaining
6765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * a copy of this software and associated documentation files (the
7765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * "Software"), to deal in the Software without restriction, including
8765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * without limitation the rights to use, copy, modify, merge, publish,
9765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * distribute, sublicense, and/or sell copies of the Software, and to
10765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * permit persons to whom the Software is furnished to do so, subject to
11765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * the following conditions:
12765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
13765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * The above copyright notice and this permission notice shall be
14765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * included in all copies or substantial portions of the Software.
15765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
16765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */
24765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
25765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// dependencies
26765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangvar peg     = require('pegjs')
27765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  , fs      = require('fs')
28765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  , path    = require('path')
29765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  , Promise = require('bluebird')
30765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  , _       = require('lodash')
31765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  , util    = require('util');
32765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
33765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
34765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// use promise-style programming rather than spaghetti callbacks
35765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun ZhangPromise.promisifyAll(fs);
36765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
37765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
38765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangvar xml2js = {
39765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
40765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // js-format specs
41765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // MODULE: <module name>
42765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // ENUMS: {
43765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   <enum name>: {
44765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     type: <enum type>,
45765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     description: <enum description>
46765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   }, ...
47765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
48765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // ENUMS_BY_GROUP: {
49765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   <enum type>: {
50765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     description: <enum group description>
51765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     members: [ <enum name>, ... ]
52765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   }, ...
53765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
54765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // METHODS: {
55765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   <method name>: {
56765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     description: <method description>,
57765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     params: {
58765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       <param name>: {
59765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //         type: <param type>,
60765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //         description: <param description >
61765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       }, ...
62765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     },
63765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     return: {
64765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       type: <return type>,
65765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       description: <return description>
66765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     }
67765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   }, ...
68765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
69765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // CLASSES: {
70765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   <class name>: {
71765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     description: <class description>,
72765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     parent: <parent class name>,
73765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     group: <group name>,
74765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     methods: { ... },
75765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     variables: {
76765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       <variable name>: {
77765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //         type: <variable type>,
78765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //         description: <variable description>
79765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //       }
80765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     },
81765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     enums: { ... },
82765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     enums_by_group: { ... }
83765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   }, ...
84765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
85765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // CLASSGROUPS: {
86765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   <group name>: {
87765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     description: <group description>,
88765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     classes: [ <class name>, ... ],
89765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     enums: { ... },
90765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //     enums_by_group: { ... }
91765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //   }, ...
92765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
93765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  MODULE: '',
94765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  ENUMS: {},
95765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  ENUMS_BY_GROUP: {},
96765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  METHODS: {},
97765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  CLASSES: {},
98765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  CLASSGROUPS: {},
99765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
100765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
101765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // baseline c -> js type mapping
102765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  TYPEMAPS: {
103765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    '^(const)?\\s*(unsigned|signed)?\\s*(int|short|long|float|double|size_t|u?int\\d{1,2}_t)?$': 'Number',
104765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    '^bool$': 'Boolean',
105765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    '^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String',  // TODO: verify that swig does this mapping
106765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    '^void\\s*\\(\\s*\\*\\s*\\)\\s*\\(\\s*void\\s*\\*\\)\\s*$': 'Function'
107765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  },
108765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
109765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
110765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // custom c -> js type mapping for pointers
111765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // ARRAY_TYPEMAPS: {
112765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //    <pointer data type>: {
113765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //      arrayType: <swig generated array type that will replace pointers of data type>,
114765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //      classes: [ <class that contains arrayType>, ... ]
115765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //    }, ...
116765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
117765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // POINTER_TYPEMAPS: {
118765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //    <class that contains pointerType>: {
119765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //      <c pointer data type>: <js swig generated pointer type that will replace pointers of data type>, ...
120765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  //    }, ...
121765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // }
122765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  ARRAY_TYPEMAPS: {},
123765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  POINTER_TYPEMAPS: {},
124765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
125765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
126765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // add command line options for this module
127765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  addOptions: function(opts) {
128765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.opts = opts;
129765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return opts
130765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      .option('-i, --inputdir [directory]', 'directory for xml files', __dirname + '/xml/mraa')
131765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      .option('-c, --custom [file]', 'json for customizations')
132765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      .option('-t, --typemaps [directory]', 'directory for custom pointer type maps')
133765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      .option('-g, --imagedir [directory]', 'directory to link to where the images will be kept', '')
134765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      .option('-s, --strict', 'leave out methods/variables if unknown type')
135765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  },
136765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
137765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
138765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // parse doxygen xml -> js-format specs
139765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // TODO: figure out whether we need to document any protected methods/variables
140765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  parse: function() {
141765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var XML_GRAMMAR_SPEC = 'grammars/xml.peg';
142765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var NAMESPACE_SPEC = xml2js.opts.inputdir + '/namespace' + xml2js.opts.module + '.xml';
143765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var CLASS_SPEC = function(c) { return xml2js.opts.inputdir + '/' + c + '.xml'; }
144765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var TYPES_SPEC = xml2js.opts.inputdir + '/types_8h.xml';
145765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.MODULE = xml2js.opts.module;
146765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return Promise.join(createXmlParser(XML_GRAMMAR_SPEC),
147765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                        xml2js.opts.typemaps ? initCustomPointerTypemaps(xml2js.opts.typemaps) : Promise.resolve(),
148765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                        fs.readFileAsync(NAMESPACE_SPEC, 'utf8'),
149765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                        fs.existsSync(TYPES_SPEC) ? fs.readFileAsync(TYPES_SPEC, 'utf8') : Promise.resolve(null),
150765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                        function(xmlparser, ignore, xml, xml_types) {
151765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (xml_types != null) {
152765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.extend(xml2js.ENUMS, getEnums(xmlparser.parse(xml_types)[0], false));
153765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.extend(xml2js.ENUMS_BY_GROUP, getEnums(xmlparser.parse(xml_types)[0], true));
154765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
155765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var spec_c = xmlparser.parse(xml)[0];
156765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      _.extend(xml2js.ENUMS, getEnums(spec_c, false));
157765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      _.extend(xml2js.ENUMS_BY_GROUP, getEnums(spec_c, true));
158765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      _.extend(xml2js.METHODS, getMethods(spec_c));
159765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      _.each(getSubclassNames(spec_c), function(className) { xml2js.CLASSES[className] = {} });
160765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var parseClasses = _.map(getSubclasses(spec_c), function(c) {
161765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        return fs.readFileAsync(CLASS_SPEC(c), 'utf8').then(function(xml) {
162765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          try {
163765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var spec_c = xmlparser.parse(xml)[0];
164765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var className = getName(spec_c);
165765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            _.extend(xml2js.CLASSES[className], {
166765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              description: getDescription(spec_c),
167765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              parent: getParent(spec_c, className),
168765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              enums: getEnums(spec_c, false, className),
169765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              enums_by_group: getEnums(spec_c, true, className),
170765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              variables: getVariables(spec_c, className),
171765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              methods: getMethods(spec_c, className)
172765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            });
173765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          } catch(e) {
174765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            console.log(e.toString() + ': class ' + className + ' was not parsed correctly.');
175765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
176765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
177765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      });
178765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var parseGroups = fs.readdirAsync(xml2js.opts.inputdir).then(function(files) {
179765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var groupxmlfiles = _.filter(files, function(fn) {
180765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return ((path.extname(fn) == '.xml') && (path.basename(fn).search(/^group/) != -1));
181765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
182765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        return Promise.all(_.map(groupxmlfiles, function(fn) {
183765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return fs.readFileAsync(xml2js.opts.inputdir + '/' + fn, 'utf8').then(function(xml) {
184765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var spec_c = xmlparser.parse(xml)[0];
185765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            if (_.isEmpty(getSubmodules(spec_c))) {
186765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              var group = getName(spec_c);
187765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              var classes = getSubclassNames(spec_c);
188765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              xml2js.CLASSGROUPS[group] = {
189765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                description: getDescription(spec_c),
190765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                classes: classes
191765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              };
192765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              _.each(classes, function(c) {
193765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                if (_.has(xml2js.CLASSES, c)) {
194765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  xml2js.CLASSES[c].group = group;
195765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                } else {
196765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  console.log('Warning: Group ' + group + ' has unknown class ' + c);
197765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                }
198765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              });
199765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            }
200765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          });
201765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }));
202765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      });
203765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return Promise.all(parseClasses.concat(parseGroups));
204765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }).then(function() {
205765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (!_.isEmpty(xml2js.CLASSGROUPS)) {
206765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        // try to categorize ungrouped classes, if any
207765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
208765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
209765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.each(ungrouped, function(c) {
210765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.each(findUsage(c), function(group) {
211765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            xml2js.CLASSGROUPS[group].classes.push(c);
212765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          });
213765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
214765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
215765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
216765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        // try to categorize ungrouped enums, if any
217765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.each(xml2js.ENUMS_BY_GROUP, function(enumGroupSpec, enumGroupName) {
218765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.each(findUsage(enumGroupName, true), function(c) {
219765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            xml2js.CLASSES[c].enums_by_group[enumGroupName] = enumGroupSpec;
220765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            _.each(enumGroupSpec.members, function(enumName) {
221765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              xml2js.CLASSES[c].enums[enumName] = xml2js.ENUMS[enumName];
222765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              delete xml2js.ENUMS[enumName];
223765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            });
224765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            delete xml2js.ENUMS_BY_GROUP[enumGroupName];
225765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          });
226765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
227765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
228765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }).then(function() {
229765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (xml2js.opts.custom && fs.existsSync(xml2js.opts.custom)) {
230765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        return fs.readFileAsync(xml2js.opts.custom, 'utf8').then(function(custom) {
231765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          try {
232765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            customizeMethods(JSON.parse(custom));
233765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          } catch(e) {
234765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            console.log('invalid custom.json, ignored. ' + e.toString());
235765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
236765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
237765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      } else {
238765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        console.log(xml2js.opts.custom ? ('Error: No such customization file exists: ' + xml2js.opts.custom) : 'No customizations given.');
239765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
240765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }).then(function() {
241765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      generateCustomPointerClasses();
242765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      validateMethods();
243765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      validateVars();
244765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return _.pick(xml2js, 'MODULE', 'ENUMS', 'ENUMS_BY_GROUP', 'METHODS', 'CLASSES', 'CLASSGROUPS');
245765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
246765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
247765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang};
248765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
249765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
250765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// create an xml parser
251765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction createXmlParser(XML_GRAMMAR_SPEC) {
252765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return fs.readFileAsync(XML_GRAMMAR_SPEC, 'utf8').then(function(xmlgrammar) {
253765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return peg.buildParser(xmlgrammar);
254765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
255765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
256765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
257765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
258765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// configure c->js typemaps from custom swig directives
259765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// TODO: many built in assumptions based on current upm file structures & .i customizations
260765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction initCustomPointerTypemaps(typemapsdir) {
261765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return fs.readdirAsync(typemapsdir).then(function(dirs) {
262765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return Promise.all(_.map(dirs, function(dir) {
263765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      // get all js*.i directives from class-specific subdirectories, to be parsed below for %typemaps directives
264765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return fs.readdirAsync(typemapsdir + '/' + dir).then(function(files) {
265765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var directive = _.find(files, function(fn) {
266765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return ((path.extname(fn) == '.i') && (path.basename(fn).search(/^js/) != -1));
267765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
268765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var data = {};
269765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        if (directive) {
270765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          data[dir] = typemapsdir + '/' + dir + '/' + directive;
271765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
272765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        return data;
273765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }).catch(function(e) {
274765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        // get all .i directives from top level directory, and parse for %array_class directives
275765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        if (e.code == 'ENOTDIR') {
276765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var fn = dir;
277765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          if (path.extname(fn) == '.i') {
278765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            return fs.readFileAsync(typemapsdir + '/' + fn, 'utf8').then(function(directives) {
279765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              var arraytypes = _.filter(directives.split(/\n/), function(line) {
280765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                return (line.search(/^%array_class/) != -1);
281765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              });
282765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              _.each(arraytypes, function(arraytype) {
283765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                var parsed = arraytype.match(/%array_class\(([A-Za-z0-9_]+)[\s]*,[\s]*([A-Za-z0-9_]+)\)/);
284765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                if (parsed) {
285765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  var from = parsed[1];
286765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  var to = parsed[2];
287765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  xml2js.ARRAY_TYPEMAPS[from] = { arrayType: to, classes: [] };
288765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                } else {
289765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                  console.log('Incorrectly parsed array_class from ' + fn + ': ' + arraytype);
290765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                }
291765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              });
292765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            });
293765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
294765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        } else {
295765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          throw e;
296765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
297765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      });
298765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }));
299765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }).then(function(__directivesFiles) {
300765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    // parse for %typemaps & %pointer_functions directives
301765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var _directivesFiles = _.filter(__directivesFiles, function(data) { return !_.isEmpty(data); });
302765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var directivesFiles = _.object(_.map(_directivesFiles, _.keys), _.flatten(_.map(_directivesFiles, _.values)));
303765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return Promise.all(_.map(directivesFiles, function(directivesFn, className) {
304765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return fs.readFileAsync(directivesFn, 'utf8').then(function(directives) {
305765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var typemaps = _.filter(directives.split(/\n/), function(line) {
306765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return (line.search(/^%typemap/) != -1);
307765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
308765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.each(typemaps, function(typemap) {
309765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var parsed = typemap.match(/%typemap\((in|out)\)[\s]+([A-Za-z0-9_]+[\s]*[\*])/);
310765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          if (parsed) {
311765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var dir = parsed[1]; // TODO: ignored for now
312765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var type = normalizePointer(parsed[2]);
313765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var datatype = getPointerDataType(type);
314765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            if (_.has(xml2js.ARRAY_TYPEMAPS, datatype)) {
315765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              xml2js.ARRAY_TYPEMAPS[datatype].classes.push(className);
316765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            } else {
317765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              console.log('Ignored typemap from ' + directivesFn + ': ' + typemap.replace('{', '') + ' (no %array_class directive found for ' + datatype + ')');
318765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            }
319765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          } else {
320765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            console.log('Ignored typemap from ' + directivesFn + ': ' + typemap.replace('{', '') + ' (only considering in/out typemaps of pointer types)');
321765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
322765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
323765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var ptrfns = _.filter(directives.split(/\n/), function(line) {
324765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return (line.search(/^%pointer_functions/) != -1);
325765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
326765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        _.each(ptrfns, function(ptrfn) {
327765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var parsed = ptrfn.match(/%pointer_functions\(([A-Za-z0-9_]+)[\s]*,[\s]*([A-Za-z0-9_]+)\)/);
328765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          if (parsed) {
329765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var from = parsed[1];
330765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            var to = parsed[2];
331765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            if (!_.has(xml2js.POINTER_TYPEMAPS, className)) {
332765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              xml2js.POINTER_TYPEMAPS[className] = {};
333765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            }
334765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            xml2js.POINTER_TYPEMAPS[className][from] = to;
335765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
336765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        });
337765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      });
338765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }));
339765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
340765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
341765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
342765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
343765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// generate class specs for custom pointer types
344765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction generateCustomPointerClasses() {
345765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var arrayTypes = _.pluck(_.values(xml2js.ARRAY_TYPEMAPS), 'arrayType');
346765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var pointerTypes = _.uniq(_.flatten(_.map(_.values(xml2js.POINTER_TYPEMAPS), _.values)));
347765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(arrayTypes, function(arrayType) {
348765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var dataType = _.findKey(xml2js.ARRAY_TYPEMAPS, function(to) { return to.arrayType == arrayType; });
349765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[arrayType] = {
350765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Array of type ' + dataType + '.',
351765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      enums: {},
352765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      enums_by_group: {},
353765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      variables: {},
354765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      methods: {}
355765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
356765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[arrayType].methods[arrayType] = {
357765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Instantiates the array.',
358765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {
359765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        nelements: {
360765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          type: 'Number',
361765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: 'number of elements in the array'
362765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
363765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      },
364765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {}
365765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
366765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[arrayType].methods.getitem = {
367765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Access a particular element in the array.',
368765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {
369765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        index: {
370765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          type: 'Number',
371765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: 'index of array to read from'
372765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        },
373765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      },
374765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {
375765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        type: getType(dataType),
376765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        description: 'the value of the element found at the given index of the array'
377765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
378765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
379765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[arrayType].methods.setitem = {
380765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Modify a particular element in the array.',
381765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {
382765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        index: {
383765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          type: 'Number',
384765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: 'index of array to write to'
385765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        },
386765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        value: {
387765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          type: getType(dataType),
388765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: 'the value to set the element found at the given index of the array'
389765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
390765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      },
391765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {}
392765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
393765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
394765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var pointerDataTypeMap = _.reduce(_.map(_.values(xml2js.POINTER_TYPEMAPS), _.invert), function(memo, typemap) {
395765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return _.extend(memo, typemap);
396765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }, {});
397765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(pointerTypes, function(pointerType) {
398765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var dataType = pointerDataTypeMap[pointerType];
399765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[pointerType] = {
400765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Proxy object to data of type ' + dataType + '.',
401765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      enums: {},
402765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      enums_by_group: {},
403765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      variables: {},
404765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      methods: {}
405765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
406765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[pointerType].methods[pointerType] = {
407765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Instantiates the proxy object.',
408765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {},
409765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {}
410765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
411765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[pointerType].methods.value = {
412765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Get the value of the object.',
413765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {},
414765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {
415765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        type: getType(dataType),
416765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        description: 'the value of the object'
417765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
418765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
419765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    xml2js.CLASSES[pointerType].methods.assign = {
420765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      description: 'Set the value of the object.',
421765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      params: {
422765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        value: {
423765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          type: getType(dataType),
424765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: 'the value to set the object to'
425765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
426765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      },
427765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return: {}
428765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    };
429765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
430765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
431765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
432765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
433765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// search for usage of a type
434765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction findUsage(type, classOnly) {
435765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var filterClasses = function(fn) { return _.without(_.map(xml2js.CLASSES, fn), undefined); };
436765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var usesType = function(classSpec, className) {
437765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var methodsOfType = (_.find(classSpec.methods, function(methodSpec, methodName) {
438765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return ((!_.isEmpty(methodSpec.return) && methodSpec.return.type == type) ||
439765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              (_.contains(_.pluck(methodSpec.params, 'type'), type)));
440765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }) != undefined);
441765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var variablesOfType = _.contains(_.pluck(classSpec.variable, 'type'), type);
442765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return ((methodsOfType || variablesOfType) ? className : undefined);
443765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  };
444765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var extendsType = function(classSpec, className) {
445765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return ((classSpec.parent == type) ? className : undefined);
446765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  };
447765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var classes = _.union(filterClasses(usesType), filterClasses(extendsType));
448765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (classOnly) {
449765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return classes;
450765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  } else {
451765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return _.without(_.uniq(_.pluck(_.pick(xml2js.CLASSES, classes), 'group')), undefined);
452765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
453765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
454765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
455765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
456765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// override autogenerated methods with custom configuration
457765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction customizeMethods(custom) {
458765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(custom, function(classMethods, className) {
459765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    _.extend(xml2js.CLASSES[className].methods, _.pick(classMethods, function(methodSpec, methodName) {
460765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return isValidMethodSpec(methodSpec, className + '.' + methodName);
461765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }));
462765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
463765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
464765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
465765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
466765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// make sure methods have valid types, otherwise warn (& don't include if strict)
467765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction validateMethods() {
468765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  xml2js.METHODS = _.pick(xml2js.METHODS, function(methodSpec, methodName) {
469765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return hasValidTypes(methodSpec, methodName);
470765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
471765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(xml2js.CLASSES, function(classSpec, className) {
472765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var valid = _.pick(classSpec.methods, function(methodSpec, methodName) {
473765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return hasValidTypes(methodSpec, className + '.' + methodName, className);
474765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
475765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (xml2js.opts.strict) {
476765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      xml2js.CLASSES[className].methods = valid;
477765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
478765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
479765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
480765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
481765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
482765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// make sure variables have valid types, otherwise warn (& don't include if strict)
483765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction validateVars() {
484765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(xml2js.CLASSES, function(classSpec, className) {
485765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var valid = _.pick(classSpec.variables, function(varSpec, varName) {
486765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return ofValidType(varSpec, className + '.' + varName, className);
487765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
488765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (xml2js.opts.strict) {
489765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      xml2js.CLASSES[className].variables = valid;
490765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
491765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
492765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
493765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
494765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
495765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// verify that the json spec is well formatted
496765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction isValidMethodSpec(methodSpec, methodName) {
497765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var valid = true;
498765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var printIgnoredMethodOnce = _.once(function() { console.log(methodName + ' from ' + path.basename(xml2js.opts.custom) + ' is omitted from JS documentation.'); });
499765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  function checkRule(rule, errMsg) {
500765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (!rule) {
501765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      printIgnoredMethodOnce();
502765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      console.log('  ' + errMsg);
503765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      valid = false;
504765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
505765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
506765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  checkRule(_.has(methodSpec, 'description'), 'no description given');
507765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  checkRule(_.has(methodSpec, 'params'), 'no params given (specify "params": {} for no params)');
508765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(methodSpec.params, function(paramSpec, paramName) {
509765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    checkRule(_.has(paramSpec, 'type'), 'no type given for param ' + paramName);
510765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    checkRule(_.has(paramSpec, 'description'), 'no description given for param ' + paramName);
511765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
512765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  checkRule(_.has(methodSpec, 'return'), 'no return given (specify "return": {} for no return value)');
513765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  checkRule(_.has(methodSpec.return, 'type'), 'no type given for return value');
514765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  checkRule(_.has(methodSpec.return, 'description'), 'no description given for return value');
515765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return valid;
516765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
517765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
518765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
519765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get enum specifications
520765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getEnums(spec_c, bygroup, parent) {
521765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var spec_js = {};
522765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var enumGroups = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
523765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var kind = getAttr(section, 'kind');
524765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return ((kind == 'enum') || (kind == 'public-type'));
525765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
526765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (enumGroups) {
527765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    _.each(enumGroups.children, function(enumGroup) {
528765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var enumGroupName = getText(getChild(enumGroup, 'name'), 'name');
529765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var enumGroupDescription = getText(getChild(enumGroup, 'detaileddescription'), 'description');
530765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var enumGroupVals = getChildren(enumGroup, 'enumvalue');
531765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (bygroup) {
532765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        spec_js[enumGroupName] = {
533765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          description: enumGroupDescription,
534765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          members: []
535765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        };
536765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
537765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      _.each(enumGroupVals, function(e) {
538765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        // TODO: get prefix as option
539765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var enumName = getText(getChild(e, 'name'), 'name').replace(/^MRAA_/, '');
540765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        var enumDescription = getText(getChild(e, 'detaileddescription'), 'description');
541765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        if (!bygroup) {
542765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          spec_js[enumName] = {
543765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            type: enumGroupName,
544765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            description: enumDescription
545765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          };
546765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        } else {
547765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          spec_js[enumGroupName].members.push(enumName);
548765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
549765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      });
550765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
551765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
552765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return spec_js;
553765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
554765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
555765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
556765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the name for the module/group/class
557765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getName(spec_c) {
558765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return getText(getChild(spec_c, 'compoundname'), 'name').replace(xml2js.opts.module + '::', '');
559765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
560765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
561765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
562765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the description for the module/group/class
563765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getDescription(spec_c) {
564765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return getText(getChild(spec_c, 'detaileddescription'), 'description');
565765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
566765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
567765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
568765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the classes (xml file names) for the given module
569765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getSubclasses(spec_c) {
570765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
571765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return getAttr(innerclass, 'refid');
572765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
573765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
574765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
575765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
576765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the classes (class names) for the given module
577765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getSubclassNames(spec_c) {
578765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
579765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return getText(innerclass).replace(xml2js.opts.module + '::', '');
580765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
581765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
582765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
583765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
584765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the submodules (xml file names) for the given module
585765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getSubmodules(spec_c) {
586765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.map(getChildren(spec_c, 'innergroup'), function(innergroup) {
587765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return getAttr(innergroup, 'refid');
588765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
589765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
590765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
591765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
592765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get parent class, if any
593765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getParent(spec_c, className) {
594765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var parent = getChild(spec_c, 'basecompoundref');
595765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (parent) {
596765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    parent = getText(parent);
597765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (!_.has(xml2js.CLASSES, parent)) {
598765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      console.log('WARNING: Class ' + className + ' has unknown parent class ' + parent);
599765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
600765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
601765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return parent;
602765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
603765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
604765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
605765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction hasParams(paramsSpec) {
606765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return !(_.isEmpty(paramsSpec) ||
607765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang           ((_.size(paramsSpec) == 1) && getText(getChild(paramsSpec[0], 'type')) == 'void'));
608765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
609765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
610765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
611765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get method specifications for top-level module or a given class
612765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// TODO: overloaded functions
613765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// TODO: functions w/ invalid parameter(s)/return
614765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getMethods(spec_c, parent) {
615765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var spec_js = {};
616765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var methods = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
617765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var kind = getAttr(section, 'kind');
618765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return ((kind == 'public-func') || (kind == 'func'));
619765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
620765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (methods) {
621765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    _.each(methods.children, function(method) {
622765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var methodName = getText(getChild(method, 'name'), 'name');
623765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (methodName[0] != '~') { // filter out destructors
624765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        try {
625765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var description = getChild(method, 'detaileddescription');
626765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var methodDescription = getText(description, 'description');
627765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var paramsSpec = getChildren(method, 'param');
628765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var params = {};
629765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          if (hasParams(paramsSpec)) {
630765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang              params = getParams(paramsSpec, getParamsDetails(description), methodName, parent);
631765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
632765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var returnSpec = getChild(method, 'type');
633765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var retval = {};
634765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          if (!_.isEmpty(returnSpec)) {
635765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            retval = getReturn(returnSpec, getReturnDetails(description), methodName, parent);
636765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          }
637765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          methodName = getUniqueMethodName(methodName, spec_js, parent);
638765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          spec_js[methodName] = {
639765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            description: methodDescription,
640765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            params: params,
641765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang            return: retval
642765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          };
643765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        } catch(e) {
644765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          console.log((parent ? (parent + '.') : '') + methodName + ' is omitted from JS documentation.');
645765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          console.log('  ' + e.toString());
646765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        }
647765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
648765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
649765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
650765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return spec_js;
651765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
652765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
653765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
654765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get a unique string to represent the name of an overloaded method
655765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getUniqueMethodName(methodName, module, parent) {
656765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (methodName in module) {
657765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    do {
658765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      methodName += '!';
659765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } while (methodName in module);
660765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
661765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return methodName;
662765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
663765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
664765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
665765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get variable specifications for a class
666765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getVariables(spec_c, parent) {
667765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var spec_js = {};
668765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var vars = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
669765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var kind = getAttr(section, 'kind');
670765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return (kind == 'public-attrib');
671765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
672765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (vars) {
673765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    _.each(_.filter(vars.children, function(variable) {
674765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return (getAttr(variable, 'kind') == 'variable');
675765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }), function(variable) {
676765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var varName = getText(getChild(variable, 'name'), 'name');
677765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var varType = getType(getText(getChild(variable, 'type')), parent);
678765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var varDescription = getText(getChild(variable, 'detaileddescription'));
679765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      spec_js[varName] = {
680765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        type: varType,
681765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        description: varDescription
682765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
683765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    });
684765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
685765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return spec_js;
686765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
687765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
688765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
689765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get return value specs of a method
690765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getReturn(spec_c, details, method, parent) {
691765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var retType = getType(getText(spec_c, 'type'), parent);
692765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var retDescription = (details ? getText(details, 'description') : '');
693765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return ((retType == 'void') ? {} : {
694765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    type: retType,
695765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    description: retDescription
696765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
697765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
698765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
699765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
700765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get paramater specs of a method
701765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getParams(spec_c, details, method, parent) {
702765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var spec_js = {};
703765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(spec_c, function(param) {
704765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    try {
705765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var paramType = getType(getText(getChild(param, 'type'), 'type'), parent);
706765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var paramName = getText(getChild(param, 'declname'), 'name');
707765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      spec_js[paramName] = { type: paramType };
708765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } catch(e) {
709765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      if (paramType == '...') {
710765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        spec_js['arguments'] = { type: paramType };
711765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      } else {
712765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        throw e;
713765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
714765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
715765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
716765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(details, function(param) {
717765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var getParamName = function(p) { return getText(getChild(getChild(p, 'parameternamelist'), 'parametername'), 'name'); }
718765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var paramName = getParamName(param);
719765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var paramDescription = getText(getChild(param, 'parameterdescription'), 'description');
720765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (_.has(spec_js, paramName)) {
721765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      spec_js[paramName].description = paramDescription;
722765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else {
723765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var msg = ' has documentation for an unknown parameter: ' + paramName + '. ';
724765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var suggestions = _.difference(_.keys(spec_js), _.map(details, getParamName));
725765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      var msgAddendum = (!_.isEmpty(suggestions) ? ('Did you mean ' + suggestions.join(', or ') + '?') : '');
726765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      console.log('Warning: ' + (parent ? (parent + '.') : '') + method + msg + msgAddendum);
727765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
728765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
729765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return spec_js;
730765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
731765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
732765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
733765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the equivalent javascript type from the given c type
734765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getType(type_c, parent) {
735765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var type_js = type_c;
736765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.find(xml2js.TYPEMAPS, function(to, from) {
737765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var pattern = new RegExp(from, 'i');
738765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (type_c.search(pattern) == 0) {
739765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      type_js = to;
740765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return true;
741765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
742765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
743765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (isPointer(type_js)) {
744765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var dataType = getPointerDataType(type_js);
745765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var className = parent.toLowerCase();
746765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (_.has(xml2js.ARRAY_TYPEMAPS, dataType) && _.contains(xml2js.ARRAY_TYPEMAPS[dataType].classes, className)) {
747765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      type_js = xml2js.ARRAY_TYPEMAPS[dataType].arrayType;
748765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else if (_.has(xml2js.POINTER_TYPEMAPS, className) && _.has(xml2js.POINTER_TYPEMAPS[className], dataType)) {
749765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      type_js = xml2js.POINTER_TYPEMAPS[className][dataType];
750765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else if (_.has(xml2js.CLASSES, dataType)) { // TODO: verify that swig does this mapping
751765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      type_js = dataType;
752765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else {
753765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      type_js = dataType + ' &#42;'
754765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
755765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
756765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return type_js;
757765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
758765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
759765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
760765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// verify that all types associated with the method are valid
761765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction hasValidTypes(methodSpec, methodName, parent) {
762765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var valid = true;
763765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var msg = (xml2js.opts.strict ? ' is omitted from JS documentation.' : ' has invalid type(s).');
764765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var printIgnoredMethodOnce = _.once(function() { console.log(methodName + msg); });
765765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  _.each(methodSpec.params, function(paramSpec, paramName) {
766765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (!isValidType(paramSpec.type, parent)) {
767765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      valid = false;
768765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      printIgnoredMethodOnce();
769765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      console.log('  Error: parameter ' + paramName + ' has invalid type ' + typeToString(paramSpec.type));
770765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
771765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
772765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (!_.isEmpty(methodSpec.return) && !isValidType(methodSpec.return.type, parent)) {
773765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    valid = false;
774765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    printIgnoredMethodOnce();
775765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    console.log('  Error: returns invalid type ' + typeToString(methodSpec.return.type));
776765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
777765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return valid;
778765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
779765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
780765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
781765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// verify that type of variable is valid
782765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction ofValidType(varSpec, varName, parent) {
783765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (isValidType(varSpec.type, parent)) {
784765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return true;
785765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  } else {
786765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    var msgAddendum = (xml2js.opts.strict ? ' Omitted from JS documentation.' : '');
787765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    console.log('Error: ' + varName + ' is of invalid type ' + typeToString(varSpec.type) + '.' + msgAddendum);
788765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return false;
789765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }
790765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
791765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
792765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
793765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// verify whether the given type is valid JS
794765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction isValidType(type, parent) {
795765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return (_.contains(_.values(xml2js.TYPEMAPS), type) ||
796765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.has(xml2js.CLASSES, type) ||
797765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.has(xml2js.ENUMS_BY_GROUP, type) ||
798765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.contains(['Buffer', 'Function', 'mraa_result_t'], type) ||
799765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          _.has((parent ? xml2js.CLASSES[parent].enums_by_group : []), type) ||
800765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          isValidPointerType(type, parent));
801765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
802765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
803765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
804765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction isValidPointerType(type, parent) {
805765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var className = parent.toLowerCase();
806765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var arrayTypemap = _.find(xml2js.ARRAY_TYPEMAPS, function(to) { return to.arrayType == type; });
807765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var valid = ((arrayTypemap && _.contains(arrayTypemap.classes, className)) ||
808765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          (_.has(xml2js.POINTER_TYPEMAPS, className) && (_.contains(_.values(xml2js.POINTER_TYPEMAPS[className]), type))));
809765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return valid;
810765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
811765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
812765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
813765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// determines whether a type looks like a c pointer
814765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction isPointer(type) {
815765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return (type.search(/\w+\s*(\*|&amp;)$/) != -1);
816765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
817765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
818765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
819765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// remove extraneous whitespace from pointer types as canonical representation
820765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction normalizePointer(ptr) {
821765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return ptr.replace(/\s*$/, '');
822765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
823765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
824765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
825765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the data type of a pointer (e.g. int is the data type of int*)
826765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getPointerDataType(ptr) {
827765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return ptr.replace(/\s*(\*|&amp;)$/, '');
828765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
829765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
830765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
831765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// print more human friendly type for error messages
832765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction typeToString(type) {
833765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return type.replace('&#42;', '*');
834765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
835765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
836765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
837765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the detailed description of a method's parameters
838765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getParamsDetails(spec_c) {
839765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var paras = getChildren(spec_c, 'para');
840765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var details = _.find(_.map(paras, function(para) {
841765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return getChild(para, 'parameterlist');
842765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }), function(obj) { return (obj != undefined); });
843765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return (details ? details.children : undefined);
844765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
845765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
846765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
847765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the detailed description of a method's return value
848765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction  getReturnDetails(spec_c) {
849765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var paras = getChildren(spec_c, 'para');
850765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.find(_.map(paras, function(para) {
851765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return getChild(para, 'simplesect');
852765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }), function(obj) { return ((obj != undefined) && (getAttr(obj, 'kind') == 'return')); });
853765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
854765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
855765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
856765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get (and flatten) the text of the given object
857765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getText(obj, why) {
858765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // TODO: links ignored for now, patched for types for
859765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  var GENERATE_LINK = function(x) { return x + ' '; }
860765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.reduce(obj.children, function(text, elem) {
861765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    if (_.isString(elem)) {
862765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return text += elem.trim() + ' ';
863765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else if (_.isPlainObject(elem)) {
864765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      switch(elem.name) {
865765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'para':
866765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += getText(elem, why) + '  \n';
867765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'ref':
868765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += GENERATE_LINK(getText(elem, why));
869765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'parameterlist':
870765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'simplesect':
871765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text; // to be handled elsewhere
872765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'programlisting':
873765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'htmlonly':
874765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text; // ignored
875765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        // TODO: html doesn't seem to work for yuidoc, using markdown for now
876765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'itemizedlist':
877765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '\n' + getText(elem, why) + '  \n  \n';
878765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'listitem':
879765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '+ ' + getText(elem, why) + '\n';
880765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'bold':
881765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '__' + getText(elem, why).trim() + '__ ';
882765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'ulink':
883765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '[' + getText(elem, why).trim() + '](' + getAttr(elem, 'url').trim() + ') ';
884765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'image':
885765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          // TODO: copy images over; hard coded for now
886765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          var fn = getAttr(elem, 'name');
887765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '  \n  \n![' + fn + '](' + xml2js.opts.imagedir + '/' + fn + ') ';
888765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'linebreak':
889765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '  \n';
890765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        case 'ndash':
891765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text += '&ndash; ';
892765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang        default:
893765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          // TODO: incomplete list of doxygen xsd implemented
894765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          console.warn('NYI Unknown Object Type: ' + elem.name);
895765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          return text;
896765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang          //throw new Error('NYI Unknown Object Type: ' + elem.name);
897765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      }
898765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    } else {
899765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw new Error('NYI Unknown Type: ' + (typeof elem));
900765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
901765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }, '').trim();
902765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
903765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
904765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
905765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the value of attribute with the given name of the given object
906765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getAttr(obj, name) {
907765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.find(obj.attr, function(item) {
908765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return item.name == name;
909765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  }).value;
910765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
911765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
912765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
913765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get the child object with the given name of the given object
914765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getChild(obj, name) {
915765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.find(obj.children, function(child) {
916765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return child.name == name;
917765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
918765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
919765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
920765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
921765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// get all children objects with the given name of the given object
922765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction getChildren(obj, name) {
923765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return _.filter(obj.children, function(child) {
924765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    return child.name == name;
925765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  });
926765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
927765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
928765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
929765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// debug helper: print untruncated object
930765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangfunction printObj(obj) {
931765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  console.log(util.inspect(obj, false, null));
932765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
933765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
934765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
935765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangmodule.exports = xml2js;