Fix #6904 - JSON output for docs / editor
[roojspacker] / roojspacker / DocParser.vala
1
2 namespace JSDOC
3 {
4         public errordomain DocParserError {
5             InvalidAugments,
6             InvalidDocChildren
7     }
8  
9  
10         public class DocParser : Object 
11         {
12                 // options - should they bee in PackerRun?
13                 static bool ignoreAnonymous =            true; 
14                 static bool treatUnderscoredAsPrivate = true;
15                 static bool explain=             false;
16  
17                 
18                 static bool has_init = false;
19                 static Walker walker ;
20             private static SymbolSet? _symbols = null;
21             
22             public static SymbolSet symbols() {
23                 if (DocParser._symbols == null) {
24                                 GLib.debug("init symbols?");
25                                 DocParser._symbols = new  SymbolSet();
26                                 //DocParser._symbols.ref(); // not sure why, by symbols keeps getting blanked.?
27                         }
28                 return DocParser._symbols;
29             }
30             static Gee.HashMap<string,SymbolSet>? _filesSymbols = null;
31             
32             static Gee.HashMap<string,SymbolSet> filesSymbols() 
33             {
34                 if (DocParser._filesSymbols == null) {
35                                 GLib.debug("init _filesSymbols?");
36                                 DocParser._filesSymbols = new     Gee.HashMap<string,SymbolSet>();
37                         }
38                 return DocParser._filesSymbols;
39                 
40             }
41                     
42             public static string currentSourceFile;
43     
44
45                 public static Gee.ArrayList<Symbol> classes()
46                 {
47                         var classes = new Gee.ArrayList<Symbol>();
48                         foreach(var symbol in DocParser.symbols().values()) {
49                                 if (symbol.isaClass()) { 
50                                         classes.add(symbol);
51                                 }
52                         }    
53                         classes.sort( (a,b) => {
54                                 return a.alias.collate(b.alias); 
55                         });
56                         return classes;
57                 }
58
59                 public static void  validateAugments()
60                 {
61                         var classes =  DocParser.classes();
62                     foreach (var cls in classes) {
63                              var ar = cls.augments.slice(0, cls.augments.size); // copy?
64                             cls.augments.clear();
65                                 for(var ii = 0  ; ii <  ar.size; ii++) {
66                                         var contributer = DocParser.symbols().getSymbol(ar[ii]);
67                                         if (contributer == null) {
68                                                 GLib.warning("Looking at Class %s, could not find augments %s", 
69                                                                 cls.alias, ar[ii]);
70                                                 continue;
71                                         }
72                                         cls.augments.add(ar[ii]); 
73                                 }
74                         }
75                 }
76
77                 public static void  fillChildClasses()
78                 {
79                          var classes =  DocParser.classes();
80                          foreach (var cls in classes) {
81                         foreach (var lookcls in classes) {
82                                         if (lookcls.augments.contains(cls.alias)) {
83                                                 var extends = "";
84                                                 if (lookcls.augments.size > 0) {
85                                                         extends = lookcls.augments.get(0);
86                                                         if ( extends  == lookcls.alias) {
87                                                                 extends = lookcls.augments.size > 1 ? lookcls.augments.get(1) : "";
88                                                         }
89                                                 }
90                                                 cls.addChildClass(lookcls.alias, extends);
91                                         }
92                                 }
93                 }
94                 }
95                 
96                 public static bool   isValidChild(Symbol cls, string cn)
97                 {
98                         var sy = DocParser.symbols().getSymbol(cn);
99                 if (sy == null) {
100                         GLib.warning("fillTreeChildren: Looking at Class %s, could not find child %s", 
101                                                 cls.alias, cn);
102                                 return false;
103                         }
104                         if (sy.isAbstract) {
105                                 GLib.debug("fillTreeChildren: checking %s child is an abstract %s", cls.alias, cn);
106                                 return false;
107                         }
108                         if (sy.tree_parent.size > 0) {
109                                 var skip  = true;
110                                 foreach (var pp in sy.tree_parent) {
111                                         if (pp == "none") {
112                                                 GLib.debug("fillTreeChildren : checking %s - skip due to tree_parent match: %s", 
113                                                         cls.alias, pp);
114                                                 return false;
115                                         }
116                                         if (pp == cls.alias) {
117                                                 skip = false;
118                                                 break;
119                                         }
120                                 }
121                                 if (skip) {
122                                         GLib.debug("fillTreeChildren : checking %s - skip due to no tree_parent match", 
123                                                         cls.alias);
124                                         return false;
125                                 }
126                         }
127                         return true;
128                         
129                         
130                 }
131                 
132                  
133                 public static void  fillTreeChildren()
134                 {
135                          // lookup symbol : builder.getSymbol()
136                          
137                          var classes =  DocParser.classes();
138                          foreach (var cls in classes) {
139                                 if (cls.tree_children.size < 1) {
140                                         GLib.debug("fillTreeChildren : skip - no children %s", cls.alias);
141                                         continue;
142                                 }
143                                 GLib.debug("fillTreeChildren : checking %s", cls.alias);
144                                 
145                                 var ar = new Gee.ArrayList<string>();
146                                 foreach(var cn in cls.tree_children) {
147                                         ar.add(cn);
148                                 }
149                                 cls.tree_children.clear();
150                         foreach(var cn in ar) {
151                                 GLib.debug("fillTreeChildren : checking %s - child %s", cls.alias, cn);
152                                 var sy = DocParser.symbols().getSymbol(cn);
153                           
154                           
155                                         
156                                         if (DocParser.isValidChild(cls, cn)) {
157                                                 GLib.debug("fillTreeChildren : checking %s - add %s",  cls.alias ,cn);
158                                                 cls.tree_children.add(cn);
159                                         }
160                                         foreach(var cc in sy.childClassesList) {
161
162                                                 if (DocParser.isValidChild(cls, cc)) {
163                                                         cls.tree_children.add(cc);
164                                                         GLib.debug("fillTreeChildren : checking %s - add %s",  cls.alias ,cc);
165                                                 }
166                                         }
167                                 }
168                         }       
169                          
170                     
171                 }
172                 
173                 public static void parse(TokenStream ts, string srcFile) 
174                 {
175  
176                     DocParser.currentSourceFile = srcFile;
177                     // not a nice way to set stuff...
178                    
179                     DocComment.shared = ""; // shared comments don't cross file boundaries
180                      
181                     DocParser.filesSymbols().set(srcFile, new SymbolSet());
182                     
183                     //Options.LOG.inform("Parser - run walker");
184                     walker = new  Walker(ts);
185                     walker.buildSymbolTree();
186                      
187                     
188                     
189                     //this.walker.walk(ts); // adds to our symbols
190                    // throw "done sym tree";
191                     //Options.LOG.inform("Parser - checking symbols");
192                     // filter symbols by option 
193                     foreach (var p in DocParser.symbols().keys()) {
194                         var symbol = DocParser.symbols().getSymbol(p);
195                         
196                        // print(JSON.stringify(symbol, null,4));
197                         
198                         if (symbol == null) continue;
199                         
200                         if (symbol.isPrivate) {
201                             DocParser.symbols().deleteSymbol(symbol.alias);
202                             DocParser.filesSymbols().get(srcFile).deleteSymbol(symbol.alias);
203                             continue;
204                         }
205                          
206                         if (symbol.is("FILE") || symbol.is("GLOBAL")) {
207                             continue;
208                         }
209                        
210                         
211                         if (symbol.alias.substring(symbol.alias.length-1) == "#") { // we don't document prototypes - this should not happen..
212                             
213                             print("Deleting Symbols (alias ends in #): " + symbol.alias);
214                             
215                             DocParser.symbols().deleteSymbol(symbol.alias);
216                             DocParser.filesSymbols().get(srcFile).deleteSymbol(symbol.alias);
217                         
218                         }
219                     }
220                     //print(prettyDump(toQDump(this.filesSymbols[Symbol.srcFile]._index,'{','}')));
221                     //print("AfterParse: " + this.symbols.keys().toSource().split(",").join(",\n   "));
222                     return; //this.symbols.toArray();
223                 }
224
225         
226                 public static void addSymbol(Symbol symbol) 
227                 {
228                     //print("PARSER addSYMBOL : " + symbol.alias);
229                     
230                         // if a symbol alias is documented more than once the last one with the user docs wins
231                         if (DocParser.symbols().hasSymbol(symbol.alias)) {
232                                 var oldSymbol = DocParser.symbols().getSymbol(symbol.alias);
233                          
234                                 if (oldSymbol.comment.isUserComment && !oldSymbol.comment.hasTags) {
235                                         if (symbol.comment.isUserComment) { // old and new are both documented
236                                                 GLib.debug("The symbol '%s' is documented more than once.",symbol.alias);
237                                                 // we use the new one???
238                                         } else { // old is documented but new isn't
239                                                 return;
240                                         }
241                                 }
242                         }
243                 
244                         // we don't document anonymous things
245                         if (DocParser.ignoreAnonymous && symbol.name.index_of("$anonymous\b") > -1) {
246                                  return;
247                         }
248
249                         // uderscored things may be treated as if they were marked private, this cascades
250                         //if (DocParser.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) {
251                         //      symbol.isPrivate = true;
252                         //}
253                  
254                         // -p flag is required to document private things
255                         if ((symbol.isInner || symbol.isPrivate) && !PackerRun.singleton().opt_doc_include_private) {
256                                  return;
257                         }
258                 
259                         // ignored things are not documented, this doesn't cascade
260                         if (symbol.isIgnored) {
261                                 return;
262                         } 
263                     // add it to the file's list... (for dumping later..)
264                     if (DocParser.currentSourceFile != null) {
265                         DocParser.filesSymbols().get(DocParser.currentSourceFile).addSymbol(symbol);
266                     }
267                   
268                         DocParser.symbols().addSymbol(symbol);
269                 }
270         
271                 public static Symbol addBuiltin(string name) 
272                 {
273                         var builtin = new Symbol.new_builtin(name);
274                     DocParser.addSymbol(builtin);
275                         return builtin;
276                 }
277         
278                 
279                 public static  void finish() {
280                         
281
282                         DocParser.symbols().relate();           
283                 
284                         // make a litle report about what was found
285                         /*
286                         if (this.conf.explain) {
287                                 var symbols = this.symbols.toArray();
288                                 var srcFile = "";
289                                 for (var i = 0, l = symbols.length; i < l; i++) {
290                                         var symbol = symbols[i];
291                                         if (srcFile != symbol.srcFile) {
292                                                 srcFile = symbol.srcFile;
293                                                 print("\n"+srcFile+"\n-------------------");
294                                         }
295                                         print(i+":\n  alias => "+symbol.alias + "\n  name => "+symbol.name+ "\n  isa => "+symbol.isa + "\n  memberOf => " + symbol.memberOf + "\n  isStatic => " + symbol.isStatic + ",  isInner => " + symbol.isInner);
296                                 }
297                                 print("-------------------\n");
298                         }
299                         */
300                 }
301                 /**
302                  * return symbols so they can be serialized.
303                  */
304                 SymbolSet symbolsToObject(string srcFile)
305                 {
306
307                     return DocParser.filesSymbols().get(srcFile);
308
309                 }
310
311         }
312 }