michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let dumpTypes = options['dump-types'].split(','); michael@0: michael@0: let interestingList = {}; michael@0: let typelist = {}; michael@0: michael@0: function interestingType(t) michael@0: { michael@0: let name = t.name; michael@0: michael@0: if (dumpTypes.some(function(n) n == name)) { michael@0: interestingList[name] = t; michael@0: typelist[name] = t; michael@0: return true; michael@0: } michael@0: michael@0: for each (let base in t.bases) { michael@0: if (base.access == 'public' && interestingType(base.type)) { michael@0: typelist[name] = t; michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: function addSubtype(t, subt) michael@0: { michael@0: if (subt.typedef === undefined && michael@0: subt.kind === undefined) michael@0: throw Error("Unexpected subtype: not class or typedef: " + subt); michael@0: michael@0: if (t.subtypes === undefined) michael@0: t.subtypes = []; michael@0: michael@0: t.subtypes.push(subt); michael@0: } michael@0: michael@0: function process_type(t) michael@0: { michael@0: interestingType(t); michael@0: michael@0: for each (let base in t.bases) michael@0: addSubtype(base.type, t); michael@0: } michael@0: michael@0: function process_decl(d) michael@0: { michael@0: if (d.typedef !== undefined && d.memberOf) michael@0: addSubtype(d.memberOf, d); michael@0: } michael@0: michael@0: function publicBases(t) michael@0: { michael@0: yield t; michael@0: michael@0: for each (let base in t.bases) michael@0: if (base.access == "public") michael@0: for each (let gbase in publicBases(base.type)) michael@0: yield gbase; michael@0: } michael@0: michael@0: function publicMembers(t) michael@0: { michael@0: for each (let base in publicBases(t)) { michael@0: for each (let member in base.members) { michael@0: if (member.access === undefined) michael@0: throw Error("Harumph: member without access? " + member); michael@0: michael@0: if (member.access != "public") michael@0: continue; michael@0: michael@0: yield member; michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Get the short name of a decl name. E.g. turn michael@0: * "MyNamespace::MyClass::Method(int j) const" into michael@0: * "Method" michael@0: */ michael@0: function getShortName(decl) michael@0: { michael@0: let name = decl.name; michael@0: let lp = name.lastIndexOf('('); michael@0: if (lp != -1) michael@0: name = name.slice(0, lp); michael@0: michael@0: lp = name.lastIndexOf('::'); michael@0: if (lp != -1) michael@0: name = name.slice(lp + 2); michael@0: michael@0: return name; michael@0: } michael@0: michael@0: /** michael@0: * Remove functions in a base class which were overridden in a derived michael@0: * class. michael@0: * michael@0: * Although really, we should perhaps do this the other way around, or even michael@0: * group the two together, but that can come later. michael@0: */ michael@0: function removeOverrides(members) michael@0: { michael@0: let overrideMap = {}; michael@0: for (let i = members.length - 1; i >= 0; --i) { michael@0: let m = members[i]; michael@0: if (!m.isFunction) michael@0: continue; michael@0: michael@0: let shortName = getShortName(m); michael@0: michael@0: let overrides = overrideMap[shortName]; michael@0: if (overrides === undefined) { michael@0: overrideMap[shortName] = [m]; michael@0: continue; michael@0: } michael@0: michael@0: let found = false; michael@0: for each (let override in overrides) { michael@0: if (signaturesMatch(override, m)) { michael@0: // remove members[i], it was overridden michael@0: members.splice(i, 1); michael@0: found = true; michael@0: } michael@0: } michael@0: if (found) michael@0: continue; michael@0: michael@0: overrides.push(m); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Generates the starting position of lines within a file. michael@0: */ michael@0: function getLineLocations(fdata) michael@0: { michael@0: yield 0; michael@0: michael@0: let r = /\n/y; michael@0: let pos = 0; michael@0: let i = 1; michael@0: for (;;) { michael@0: pos = fdata.indexOf('\n', pos) + 1; michael@0: if (pos == 0) michael@0: break; michael@0: michael@0: yield pos; michael@0: i++; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Find and return the doxygen comment immediately prior to the location michael@0: * object that was passed in. michael@0: * michael@0: * @todo: parse doccomment data such as @param, @returns michael@0: * @todo: parse comments for markup michael@0: */ michael@0: function getDocComment(loc) michael@0: { michael@0: let fdata = read_file(loc.file); michael@0: let linemap = [l for (l in getLineLocations(fdata))]; michael@0: michael@0: if (loc.line >= linemap.length) { michael@0: warning("Location larger than actual header: " + loc); michael@0: return <>; michael@0: } michael@0: michael@0: let endpos = linemap[loc.line - 1] + loc.column - 1; michael@0: let semipos = fdata.lastIndexOf(';', endpos); michael@0: let bracepos = fdata.lastIndexOf('}', endpos); michael@0: let searchslice = fdata.slice(Math.max(semipos, bracepos) + 1, endpos); michael@0: michael@0: let m = searchslice.match(/\/\*\*[\s\S]*?\*\//gm); michael@0: if (m === null) michael@0: return <>; michael@0: michael@0: let dc = m[m.length - 1].slice(3, -2); michael@0: dc = dc.replace(/^\s*(\*+[ \t]*)?/gm, ""); michael@0: michael@0: return
{dc}
; michael@0: } michael@0: michael@0: function typeName(t) michael@0: { michael@0: if (t.name !== undefined) michael@0: return t.name; michael@0: michael@0: if (t.isPointer) michael@0: return "%s%s*".format(t.isConst ? "const " : "", typeName(t.type)); michael@0: michael@0: if (t.isReference) michael@0: return "%s%s&".format(t.isConst ? "const " : "", typeName(t.type)); michael@0: michael@0: return t.toString(); michael@0: } michael@0: michael@0: function publicBaseList(t) michael@0: { michael@0: let l =