6e2c0598747bfe9a0994ba96d88f43d95976df35
[gnome.introspection-doc-generator] / JSDOC / SymbolSet.js
1 //<script type="text/javascript">
2
3  
4 XObject         = imports.XObject.XObject;
5 Options         = imports.BuildDocs.Options;
6 Parser          = imports.Parser.Parser;
7 Symbol          = imports.Symbol.Symbol;
8 DocComment      = imports.DocComment.DocComment;
9
10
11 SymbolSet = XObject.define(
12     function() {
13         this.init();
14     },
15     Object,
16     {
17         
18         init : function() {
19             this._index = {};
20         },
21
22         keys : function() {
23             var found = [];
24             for (var p in this._index) {
25                 found.push(p);
26             }
27             return found;
28         },
29
30
31         hasSymbol : function(alias) {
32             return this.keys().indexOf(alias) > -1;
33         },
34
35         addSymbol : function(symbol) {
36             print("ADDING SYMBOL:"+symbol.alias.toString());
37             
38             if (this.hasSymbol(symbol.alias)) {
39                 Options.LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
40             }
41             this._index[symbol.alias] = symbol;
42         },
43
44         getSymbol : function(alias) {
45             
46             if (this.hasSymbol(alias)) return this._index[alias];
47             return false;
48         },
49
50         toArray : function() {
51             var found = [];
52             for (var p in this._index) {
53                 found.push(this._index[p]);
54             }
55             return found;
56         },
57
58         deleteSymbol : function(alias) {
59             if (!this.hasSymbol(alias)) return;
60             delete this._index[alias];
61         },
62
63         renameSymbol : function(oldName, newName) {
64             // todo: should check if oldname or newname already exist
65             if (typeof(this._index[oldName]) == "undefined") {
66                 throw "Cant rename " + oldName + " to " + newName + " As it doesnt exist";
67                }
68             this._index[newName] = this._index[oldName];
69             this.deleteSymbol(oldName);
70             this._index[newName].alias = newName;
71             return newName;
72         },
73
74         relate : function() {
75             this.resolveBorrows();
76             this.resolveMemberOf();
77             this.resolveAugments();
78         },
79
80         resolveBorrows : function() {
81             for (p in this._index) {
82                 var symbol = this._index[p];
83                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
84                 
85                 var borrows = symbol.inherits;
86                 for (var i = 0; i < borrows.length; i++) {
87                     var borrowed = this.getSymbol(borrows[i].alias);
88                     if (!borrowed) {
89                         Options.LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
90                         continue;
91                     }
92                     
93                     var borrowAsName = borrows[i].as;
94                     var borrowAsAlias = borrowAsName;
95                     if (!borrowAsName) {
96                         Options.LOG.warn("Malformed @borrow, 'as' is required.");
97                         continue;
98                     }
99                     
100                     if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
101                         borrowAsName = borrowAsName.replace(borrowed.alias, "")
102                     }
103                     else {
104                         var joiner = "";
105                         if (borrowAsName.charAt(0) != "#") joiner = ".";
106                         borrowAsAlias = borrowed.alias + joiner + borrowAsName;
107                     }
108                     
109                     borrowAsName = borrowAsName.replace(/^[#.]/, "");
110                             
111                     if (this.hasSymbol(borrowAsAlias)) continue;
112
113                     var clone = borrowed.clone();
114                     clone.name = borrowAsName;
115                     clone.alias = borrowAsAlias;
116                     this.addSymbol(clone);
117                 }
118             }
119         },
120
121         resolveMemberOf : function() {
122             for (var p in this._index) {
123                 var symbol = this.getSymbol(p);
124                 
125                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
126                 
127                 // the memberOf value was provided in the @memberOf tag
128                 else if (symbol.memberOf) {
129                     var parts = symbol.alias.match(new RegExp("^("+symbol.memberOf+"[.#-])(.+)$"));
130                     
131                     // like foo.bar is a memberOf foo
132                     if (parts) {
133                         symbol.memberOf = parts[1];
134                         symbol.name = parts[2];
135                     }
136                     // like bar is a memberOf foo
137                     else {
138                         var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
139                         if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
140                         
141                         this.renameSymbol(p, symbol.memberOf + symbol.name);
142                     }
143                 }
144                 // the memberOf must be calculated
145                 else {
146                     var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
147                     if (parts) {
148                         symbol.memberOf = parts[1];
149                         symbol.name = parts[2];                         
150                     }
151                 }
152
153                 // set isStatic, isInner
154                 if (symbol.memberOf) {
155                     switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
156                         case '#' :
157                             symbol.isStatic = false;
158                             symbol.isInner = false;
159                             break;
160                             
161                         case '.' :
162                             symbol.isStatic = true;
163                             symbol.isInner = false;
164                             break;
165                             
166                         case '-' :
167                             symbol.isStatic = false;
168                             symbol.isInner = true;
169                             break;
170                             
171                     }
172                 }
173                 
174                 // unowned methods and fields belong to the global object
175                 if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
176                     symbol.memberOf = "_global_";
177                 }
178                 
179                 // clean up
180                 if (symbol.memberOf.match(/[.#-]$/)) {
181                     symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
182                 }
183                 //print("looking for memberOf: " + symbol.memberOf + " FOR " + symbol.alias);
184                 // add to parent's methods or properties list
185                 if (symbol.memberOf) {
186                     var container = this.getSymbol(symbol.memberOf);
187                     if (!container) {
188                         if (SymbolSet.isBuiltin(symbol.memberOf)) {
189                             container = Parser.addBuiltin(symbol.memberOf);
190                         }
191                         else {
192                            // print("symbol NOT a BUILT IN - createing a container");
193                             // Eg. Ext.y.z (missing y)
194                             // we need to add in the missing symbol...
195                             container = new Symbol(symbol.memberOf, [], "OBJECT", new DocComment(""));
196                             container.isNamespace = true;
197                             this.addSymbol( container );
198                            // print(container.toSource());
199                             //container = this.getSymbol(symbol.memberOf);
200                             // fake container ... so dont ad symbols to it..
201                             continue;
202                             container = false;
203                             //LOG.warn("Can't document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
204                             //LOG.warn("We only have the following symbols: \n" + 
205                             //    this.keys.toSource());
206                         }
207                     }
208                     
209                     if (container && !container.isNamespace) container.addMember(symbol);
210                 }
211             }
212         },
213
214         resolveAugments : function() {
215             // does this sort out multiple extends???
216             for (var p in this._index) {
217                 var symbol = this.getSymbol(p);
218                 this.buildAugmentsList(symbol); /// build heirachy of inheritance...
219                 if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
220                 
221                 var augments = symbol.augments;
222                 for(var ii = 0, il = augments.length; ii < il; ii++) {
223                     var contributer = this.getSymbol(augments[ii]);
224                     
225                     
226                     
227                     if (contributer) {
228                         contributer.childClasses.push(symbol.alias);
229                         symbol.inheritsFrom.push(contributer.alias);
230                         if (!isUnique(symbol.inheritsFrom)) {
231                             Options.LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
232                         }
233                         else {
234                             var cmethods = contributer.methods;
235                             var cproperties = contributer.properties;
236                             var cfgs = contributer.cfgs;
237                             for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {   
238                                 symbol.inherit(cmethods[ci]);
239                             }
240                             for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
241                                 symbol.inherit(cproperties[ci]);
242                             }
243                             for (var ci in cfgs) {
244                                 symbol.addConfig(cfgs[ci]);
245                             }
246                             
247                                 
248                         }
249                     }
250                     else {
251                         
252                         Options.LOG.warn("Can't augment contributer: '"+augments[ii]+"', not found. FOR: " + symbol.alias);
253                         
254                         //LOG.warn("We only have the following symbols: \n" + 
255                           //      this.keys().toSource().split(",").join(",    \n"));
256                        }
257
258                 }
259             }
260         },
261
262         buildAugmentsList : function(symbol)
263         {
264             // basic idea is to add all the child extends to the parent.. without looping forever..
265             
266             if (!symbol.augments.length) {
267                 return;
268             }
269             
270             var _t = this;
271             print("buildAugmentsList:" + symbol.alias);
272             var addAugments = function (alist, forceit) { // returns number added..
273                 if (!alist.length) {
274                     return 0;
275                 }
276                 print("buildAugmentsList:addAugments" + alist.length);
277                 var rval = 0;
278                 for(var ii = 0; ii < alist.length; ii++) {
279                     print("getAlias:" + alist[ii]);
280                     if (alist[ii] == symbol.alias) {
281                         continue;
282                     }
283                     var contributer = _t.getSymbol(alist[ii]);
284                     if (!contributer) {
285                         continue;
286                     }
287                     
288                     if (!forceit && symbol.augments.indexOf(alist[ii]) > -1) {
289                         continue;
290                     }
291                     if (symbol.augments.indexOf(alist[ii]) < 0) {
292                         symbol.augments.push(alist[ii]);
293                     }
294                         
295                     
296                     addAugments(contributer.augments,false);
297                     
298                     rval++;
299                 }
300                 print("buildAugmentsList: ADDED:" + rval);
301                 return rval;
302             }
303             addAugments(symbol.augments, true);
304             //while(addAugments(symbol.augments) >  0) { }
305             
306         }
307 })
308
309 SymbolSet.isBuiltin = function(name) {
310     return (SymbolSet.isBuiltin.coreObjects.indexOf(name) > -1);
311 }
312 SymbolSet.isBuiltin .coreObjects = [
313     '_global_', 'Array', 'Boolean', 'Date', 'Function', 
314     'Math', 'Number', 'Object', 'RegExp', 'String'
315 ];