e68e742debabe0b25d1097b7cc2898ddaf5f33b5
[roojspacker] / roojspacker / DocTag.vala
1
2
3 namespace JSDOC 
4 {
5         public enum DocTagTitle
6         {
7                 NO_VALUE,
8                 PARAM,
9                 PROPERTY,
10                 CFG,
11                 EXAMPLE,
12                 SINGLETON,
13                 AUTHOR,
14                 METHOD,
15                 DESC,
16                 OVERVIEW,
17                 SINCE,
18                 CONSTANT,
19                 VERSION,
20                 DEPRECATED,
21  
22                 SEE,
23                 CLASS,
24                 NAMESPACE,
25                 CONSTRUCTOR,
26                 STATIC,
27  
28                 
29                 INNER,
30                 FIELD,
31                 FUNCTION,
32                 EVENT,
33                 NAME,
34                 RETURN,
35                 THROWS,
36                 REQUIRES,
37                 TYPE,
38                 PRIVATE,
39                 IGNORE,
40                 ARGUMENTS,
41                 EXTENDS,
42                 DEFAULT,
43                 MEMBEROF,
44                 PUBLIC,
45                 SCOPE,
46                 SCOPEALIAS
47   
48         }
49         
50         errordomain DocTagException {
51                 NO_TITLE,
52                 INVALID_TITLE,
53                 INVALID_NAME,
54                 INVALID_TYPE
55         }
56
57
58         public class DocTag : Object 
59         {
60
61                 public DocTagTitle title = DocTagTitle.NO_VALUE;
62                 public string type = "";  // eg.. boolean / string etc..., may be xxxx|bbbb - eg. optional types
63                 public string name = ""; // eg. "title" << a property name etc...
64                 public bool isOptional = false;
65                 public string defaultValue = "";
66                 public string desc = "";
67                 public Gee.ArrayList<string> optvalues;
68                 public string memberOf = ""; // set by add addMember..
69
70                 public string asString()
71                 {
72                         return "DocTag: title=%s name=%s type=%s  desc=%s".printf(
73                                 this.title.to_string(),
74                                 this.name,
75                                 this.type,
76                                 this.desc
77                         );
78                 }
79         
80  
81                          
82         
83         
84                 public DocTag (string in_src)
85                 {
86                     
87                     GLib.debug("Parsing Tag: %s", in_src);
88                     
89                      
90                     
91                     
92                     this.optvalues = new Gee.ArrayList<string>();
93                     
94                     var src = in_src;
95                         
96             try {
97                 src = this.nibbleTitle(src);
98                 
99                 src = this.nibbleType(src);
100                 
101
102                 // only some tags are allowed to have names.
103                 if (
104                         this.title == DocTagTitle.PARAM ||
105                         this.title == DocTagTitle.PROPERTY || 
106                         this.title == DocTagTitle.CFG) { // @config is deprecated
107                     src = this.nibbleName(src);
108                 }
109             }
110             catch(DocTagException e) {
111                 GLib.debug("Failed to parse tag: '%s' = error = %s", in_src, e.message);
112                 // only throw if in 'strict'??
113                 //throw e;
114                 return;
115             }
116             
117             // if type == @cfg, and matches (|....|...)
118             
119             src = src.strip();
120  
121             MatchInfo mi = null;
122             
123             if (this.title ==  DocTagTitle.CFG && /^\([^)]+\)/.match_all(src, 0, out mi )) {
124                     
125                                 var ms = mi.fetch(0);
126                                 GLib.debug("Got Opt list: %s", ms);
127                                 
128                                 ms = ms.substring(1,ms.length-2);
129                                 if (ms.contains("|")) {
130                                         var ar = ms.split("|");
131                                         for (var i =0 ; i < ar.length;i++) {
132                                                 optvalues.add(ar[i].strip());
133                                         }
134                                         src = src.substring(ms.length, src.length - ms.length);                   
135                     
136                 } 
137                 
138             }
139             
140             
141             this.desc = src; // whatever is left
142             
143             // example tags need to have whitespace preserved
144             if (this.title != DocTagTitle.EXAMPLE) {
145                         this.desc = this.desc.strip();
146                 }
147             
148
149                 
150         
151
152                 }
153         
154         
155                 /**
156                     Find and shift off the title of a tag.
157                     @param {string} src
158                     @return src
159                  */
160                 private string nibbleTitle (string src) throws DocTagException
161                 {
162                     //GLib.debug("nibbleTitle: %s", src);
163                     MatchInfo mi;
164                      
165                     if(! /^\s*(\S+)\s*(?:\s([\s\S]*))?$/.match_full(src, src.length, 0, 0, out mi) || 
166                             mi.get_match_count() < 2)  {
167                                 throw new DocTagException.NO_TITLE("missing title");
168                                 return src;
169                     }
170                     
171                     //GLib.debug("nibbleTitle: regexmatches %d : %s",
172                     //           mi.get_match_count(), 
173                     //           mi.fetch(1).up());
174                     
175                     EnumClass enumc = (EnumClass) typeof (DocTagTitle).class_ref ();
176
177                     unowned EnumValue? eval = enumc.get_value_by_name ( "JSDOC_DOC_TAG_TITLE_"+  mi.fetch(1).up());
178                     if (eval == null) {
179                                 throw new DocTagException.INVALID_TITLE("title not supported ??");
180                                 return src;
181                     }
182                     this.title = (DocTagTitle) eval.value;
183                     return mi.get_match_count() > 2 ? mi.fetch(2) : "";
184
185                 }
186                  
187                   /**
188             Find and shift off the type of a tag.
189             @requires frame/String.js
190             @param {string} src
191             @return src
192          */
193         private string nibbleType(string src) 
194         {
195                     MatchInfo mi;
196             if(! /^\s*\{/.match_all(src, 0, out mi)) {
197                    return src;
198             }
199             int start;
200             int stop;
201               
202                         this.balance(src,'{', '}', out start, out stop);
203                         //GLib.debug("nibble type: %s %d, %d", src, start,stop);
204             if (stop == -1) {
205                 throw new DocTagException.INVALID_TYPE("Malformed comment tag ignored. Tag type requires an opening { and a closing }: ") ;
206                 return src;
207             }
208             this.type = src.substring(start+1,stop-1).strip();
209             this.type = this.type.replace(",", "|"); // multiples can be separated by , or |
210             return src.substring(stop+1, -1);
211             
212         }
213          
214          
215          
216         /**
217             Find and shift off the name of a tag.
218             @requires frame/String.js
219             @param {string} src
220             @return src
221          */
222                 private string nibbleName( string in_src) throws DocTagException
223         {
224
225            
226             var src = in_src.strip();
227             //GLib.debug("nibbleName: %s", in_src);
228             
229             // is optional?
230             if (src.get(0) == '[') {
231                         int start, stop;
232                  this.balance(src,'[', ']', out start, out stop);
233                 if (stop == -1) {
234                     throw new  DocTagException.INVALID_NAME("Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: ");
235                     return src;
236                 }
237                 this.name = src.substring(start+1, stop).strip();
238                 this.isOptional = true;
239                 
240                 src = src.substring(stop+1);
241                 
242                 // has default value?
243                 var nameAndValue = this.name.split("=");
244                 if (nameAndValue.length > 1) {
245                         var oname = this.name;
246                     this.name = nameAndValue[0].strip();
247
248                     this.defaultValue = oname.substring( nameAndValue[0].length + 1 , nameAndValue[0].length + 1 - oname.length); /// what about
249                 }
250                 GLib.debug("got name %s", this.name);                
251                 return src.substring(stop+1, stop+1-src.length);
252             }
253                         // not encased with [ ]
254
255                     MatchInfo mi;
256
257             if (/^(\S+)(?:\s([\s\S]*))?$/.match_full(src, src.length, 0, 0,  out mi)) {
258                         this.name = mi.fetch(1);
259                         GLib.debug("got name %s", this.name);
260                                 return mi.get_match_count() > 2 ? mi.fetch(2) : "";
261             }
262                 
263
264             return src;
265         }
266          
267          
268         private void balance(string str, char open, char close, out int start, out int stop) {
269             start = 0;
270             stop  =-1;
271             while (str.get(start) != open) {
272                 if (start == str.length) {
273                         return;
274                         }
275                 start++;
276             }
277             
278             stop = start +1;
279             var balance = 1;
280             while (stop < str.length) {
281                 if (str.get(stop) == open) balance++;
282                 if (str.get(stop) == close) balance--;
283                 if (balance == 0) break;
284                 stop++;
285                 if (stop == str.length) {
286                         stop = -1;
287                         return;
288                         }
289             }
290             
291
292                 }
293                 
294                 public Json.Array optvalue_as_json_array()
295                 {
296                         var ret = new Json.Array();
297                         foreach (var str in this.optvalues ) {
298                                 ret.add_string_element(str);
299                         }
300                         return ret;
301                         
302                         
303                 }
304                 
305         }
306 }
307         
308