Fix #6894 - debugging generator
[roojspacker] / roojspacker / SymbolSet.vala
1  
2 namespace JSDOC {
3
4         public class SymbolSet  : Object {
5
6                 private Gee.HashMap<string,Symbol> __index = null;
7                 
8                 
9                 public Json.Object toJson()
10                 {
11                         var ret = new Json.Object();
12                          foreach(var k in this._index.keys) {
13                 ret.set_object_member(k, this._index.get(k).toJson());
14                 }
15                 return ret;
16                 }
17                 
18                 
19                 public Gee.HashMap<string,Symbol> _index {
20                         get {
21                                 if (this.__index == null) {
22                                         GLib.debug("Creating new Symbolset array");
23                                         this.__index = new Gee.HashMap<string,Symbol>();
24                                 }
25                                 return this.__index;
26                         }
27                 }
28                  
29                 public SymbolSet ()
30                 {
31
32                 }
33                  
34
35         public Gee.ArrayList<string> keys() 
36         {
37             var  r= new Gee.ArrayList<string>();
38             foreach(var k in this._index.keys) {
39                 r.add(k);
40                 }
41                 return r;
42
43         }
44          public Gee.ArrayList<Symbol> values() 
45         {
46             var  r= new Gee.ArrayList<Symbol>();
47             foreach(var k in this._index.values) {
48                 r.add(k);
49                 }
50                 return r;
51
52         }
53
54         public bool hasSymbol(string alias) 
55         {
56             return this._index.has_key(alias);
57             //return this.keys().indexOf(alias) > -1;
58         }
59
60         public void addSymbol (Symbol symbol) {
61              GLib.debug("ADDING SYMBOL: %s",symbol.alias);
62             
63              
64             if (this.hasSymbol(symbol.alias)) {
65                 GLib.warning("Overwriting symbol documentation for: %s.",symbol.alias);
66             }
67             this._index.set(symbol.alias,  symbol);
68         }
69
70         public Symbol? getSymbol (string alias) {
71             
72             if (this.hasSymbol(alias)) return this._index.get(alias);
73             return null;
74         }
75 /*/
76         toArray : function() {
77             var found = [];
78             for (var p in this._index) {
79                 found.push(this._index[p]);
80             }
81             return found;
82         },
83         */
84         /**
85          * for serializing
86          *
87         toJSON : function() {
88             return {
89                 '*object' : 'SymbolSet',
90                 _index : this._index
91             };
92             
93         },
94 */
95
96         public void deleteSymbol  (string alias) {
97             if (!this.hasSymbol(alias)) return;
98             this._index.unset(alias);
99         } 
100
101         public string renameSymbol (string oldName, string newName) {
102             // todo: should check if oldname or newname already exist
103             if (!this.hasSymbol(oldName)) {
104                 GLib.error("Cant rename " + oldName + " to " + newName + " As it doesnt exist");
105             } 
106             this._index.set(newName, this._index.get(oldName));
107             this.deleteSymbol(oldName);
108             this._index.get(newName).alias = newName;
109             return newName;
110         }
111
112         public void relate() 
113         {
114             GLib.debug("RELATE called");
115             foreach(var s in this._index.keys) {
116                 GLib.debug("%s", this._index.get(s).asString());
117                 }
118             this.resolveBorrows();
119             this.resolveMemberOf();
120             this.resolveAugments();
121                          GLib.debug("AFTER RELATE called");
122                 foreach(var s in this._index.keys) {
123                 GLib.debug("%s", this._index.get(s).asString());
124                 }
125         }
126
127         void resolveBorrows() 
128         {
129
130             return; // this code is not needed- we do not use @inherits
131             /*
132             foreach (var p in this._index.keys) {
133                 var symbol = this._index.get(p);
134                 
135                 
136                 
137                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
138                 
139                 var borrows = symbol.inherits;
140                 for (var i = 0; i < borrows.size; i++) {
141                     var borrowed = this.getSymbol(borrows.get(i).alias);
142                     if (!borrowed) {
143                         imports.BuildDocs.Options.LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
144                         continue;
145                     }
146                     
147                     var borrowAsName = borrows[i].as;
148                     var borrowAsAlias = borrowAsName;
149                     if (!borrowAsName) {
150                         imports.BuildDocs.Options.LOG.warn("Malformed @borrow, 'as' is required.");
151                         continue;
152                     }
153                     
154                     if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
155                         borrowAsName = borrowAsName.replace(borrowed.alias, "");
156                     }
157                     else {
158                         var joiner = "";
159                         if (borrowAsName.charAt(0) != "#") joiner = ".";
160                         borrowAsAlias = borrowed.alias + joiner + borrowAsName;
161                     }
162                     
163                     borrowAsName = borrowAsName.replace(/^[#.]/, "");
164                             
165                     if (this.hasSymbol(borrowAsAlias)) continue;
166
167                     var clone = borrowed.clone();
168                     clone.name = borrowAsName;
169                     clone.alias = borrowAsAlias;
170                     this.addSymbol(clone);
171                 }
172             }
173                         */
174         }
175
176         void resolveMemberOf () 
177         {
178             if (this._index.keys.size < 1) {
179                     return;
180             }
181             foreach (var p in this.keys()) {
182                 var symbol = this.getSymbol(p);
183                 
184                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
185                 
186                 // the memberOf value was provided in the @memberOf tag
187                 else if (symbol.memberOf.length > 0) {
188                         var regex = new GLib.Regex("^("+symbol.memberOf+"[.#-])(.+)$");
189                         GLib.MatchInfo minfo;
190                     var parts = regex.match_full(symbol.alias, -1, 0, 0 , out minfo);
191                     
192                     // like foo.bar is a memberOf foo
193                     if (parts) {                         
194                                 
195                         symbol.memberOf = minfo.fetch(1);
196                         symbol.private_name = minfo.fetch(2);
197                     }
198                     // like bar is a memberOf foo
199                     else {
200                         var joiner = symbol.memberOf.substring(symbol.memberOf.length-1);
201                         if (!/[.#-]/.match(joiner)) symbol.memberOf += ".";
202                         
203                         this.renameSymbol(p, symbol.memberOf + symbol.name);
204                     }
205                 }
206                 // the memberOf must be calculated
207                 else {
208                         GLib.MatchInfo minfo;                
209                     var parts = /^(.*[.#-])([^.#-]+)$/.match_full(symbol.alias, -1, 0, 0 , out minfo);
210
211                     if (parts) {
212                         symbol.memberOf = minfo.fetch(1);
213                         symbol.private_name = minfo.fetch(2);
214                     }
215                 }
216
217                 // set isStatic, isInner
218                 if (symbol.memberOf.length > 0) {
219                     switch (symbol.memberOf[symbol.memberOf.length-1]) {
220                         case '#' :
221                             symbol.isStatic = false;
222                             symbol.isInner = false;
223                             break;
224                             
225                         case '.' :
226                             symbol.isStatic = true;
227                             symbol.isInner = false;
228                             break;
229                             
230                         case '-' :
231                             symbol.isStatic = false;
232                             symbol.isInner = true;
233                             break;
234                             
235                     }
236                 }
237                  
238                 // unowned methods and fields belong to the global object
239                 if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
240                     symbol.memberOf = "_global_";
241                 }
242                 
243                 // clean up
244                 if (/[.#-]$/.match(symbol.memberOf)) {
245                     symbol.memberOf = symbol.memberOf.substring(0, symbol.memberOf.length-1);
246                 }
247                 //print("looking for memberOf: " + symbol.memberOf + " FOR " + symbol.alias);
248                 // add to parent's methods or properties list
249                 if (symbol.memberOf.length > 0) {
250                     var container = this.getSymbol(symbol.memberOf);
251                     if (container == null) {
252                         if (SymbolSet.isBuiltin(symbol.memberOf)) {
253                             container = DocParser.addBuiltin(symbol.memberOf);
254                         }
255                         else {
256                            // print("symbol NOT a BUILT IN - createing a container");
257                             // Eg. Ext.y.z (missing y)
258                             // we need to add in the missing symbol...
259                             container = new Symbol.new_populate_with_args(
260                                 symbol.memberOf, new Gee.ArrayList<string>(), 
261                                                 "OBJECT", new DocComment(""));
262                             container.isNamespace = true;
263                             this.addSymbol( container );
264                            // print(container.toSource());
265                             //container = this.getSymbol(symbol.memberOf);
266                             // fake container ... so dont ad symbols to it..
267                             continue;
268                             container = null;
269                             //LOG.warn("Can't document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
270                             //LOG.warn("We only have the following symbols: \n" + 
271                             //    this.keys.toSource());
272                         }
273                     }
274                     
275                     if (container != null && !container.isNamespace) {
276                          container.addMember(symbol);
277                          }
278                 }
279             }
280
281         }
282
283         void resolveAugments () 
284         {
285             // does this sort out multiple extends???
286             
287             foreach (var p in this._index.keys) {
288                 var symbol = this.getSymbol(p);
289                 this.buildAugmentsList(symbol); /// build heirachy of inheritance...
290                 if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
291                 
292                 var augments = symbol.augments;
293                 for(var ii = 0, il = augments.size; ii < il; ii++) {
294                     var contributer = this.getSymbol(augments[ii]);
295                     
296                      
297                     if (contributer != null) {
298                         contributer.childClasses.add(symbol.alias);
299                         symbol.inheritsFrom.add(contributer.alias);
300                         //if (!isUnique(symbol.inheritsFrom)) {
301                         //    imports.BuildDocs.Options.LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
302                         //}
303                         //else {
304                             var cmethods = contributer.methods;
305                             var cproperties = contributer.properties;
306                             var cfgs = contributer.cfgs;
307                             for (var ci = 0, cl = cmethods.size; ci < cl; ci++) {   
308                                 symbol.inherit(cmethods[ci]);
309                             } 
310                             for (var ci = 0, cl = cproperties.size; ci < cl; ci++) {
311                                 symbol.inherit(cproperties[ci]);
312                             }
313                             foreach (var ci in cfgs.keys) {
314                                 symbol.addConfig(cfgs[ci]);
315                             }
316                             
317                                 
318                         //}
319                     }
320                     else {
321                         GLib.warning("Can't augment contributer: '%s', not found. FOR: %s",
322                                 augments[ii], symbol.alias
323                         );
324                         //LOG.warn("We only have the following symbols: \n" + 
325                           //      this.keys().toSource().split(",").join(",    \n"));
326                        }
327         
328                 }
329             }
330             
331         }
332
333
334                  void addAugments (Symbol symbol, Gee.ArrayList<string> alist, bool forceit) 
335                  { // returns number added..
336                 if (alist.size < 1) {
337                     return;
338                 }
339                 //print("buildAugmentsList:addAugments" + alist.length);
340                 //var rval = 0;
341                 for(var ii = 0; ii < alist.size; ii++) {
342                     //print("getAlias:" + alist[ii]);
343                     if (alist[ii] == symbol.alias) {
344                         continue;
345                     }
346                     var contributer = this.getSymbol(alist[ii]);
347                     if (contributer == null) {
348                         continue;
349                     }
350                     
351                     if (!forceit && symbol.augments.contains(alist[ii])) {
352                         continue;
353                     }
354                     if (symbol.augments.index_of(alist[ii]) < 0) {
355                         symbol.augments.add(alist[ii]);
356                     }
357                         
358                     
359                     this.addAugments(symbol, contributer.augments,false);
360                     
361                     //rval++;
362                 }
363                // print("buildAugmentsList: ADDED:" + rval);
364                // return rval;
365             }
366
367         void buildAugmentsList (Symbol symbol)
368         {
369                 
370                 this.addAugments(symbol, symbol.augments, true);
371                 
372             
373             
374         }
375         public static bool isBuiltin(string name)
376                 {
377                         for (var i =0 ; i < SymbolSet.coreObjects.length; i++ ){ 
378                                 if (name ==  SymbolSet.coreObjects[i]) {
379                                         return true;
380                                 }
381                         }
382                         return false;
383                 }
384                 static string[] coreObjects  = {
385                         "_global_", "Array" , "Boolean", "Date", "Function", 
386                             "Math", "Number", "Object", "RegExp", "String"
387                 };
388          
389         }
390         
391 }
392
393