put the optional values in the values property
[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                                 var ms = mi.fetch(0);
125                                 ms = ms.substring(1,ms.length-2);
126                                 if (ms.contains("|")) {
127                                         var ar = ms.split("|");
128                                         for (var i =0 ; i < ar.length;i++) {
129                                                 optvalues.add(ar[i].strip());
130                                         }
131                                         src = src.substring(ms.length, src.length - ms.length);                   
132                     
133                 } 
134                 
135             }
136             
137             
138             this.desc = src; // whatever is left
139             
140             // example tags need to have whitespace preserved
141             if (this.title != DocTagTitle.EXAMPLE) {
142                         this.desc = this.desc.strip();
143                 }
144             
145
146                 
147         
148
149                 }
150         
151         
152                 /**
153                     Find and shift off the title of a tag.
154                     @param {string} src
155                     @return src
156                  */
157                 private string nibbleTitle (string src) throws DocTagException
158                 {
159                     //GLib.debug("nibbleTitle: %s", src);
160                     MatchInfo mi;
161                      
162                     if(! /^\s*(\S+)\s*(?:\s([\s\S]*))?$/.match_full(src, src.length, 0, 0, out mi) || 
163                             mi.get_match_count() < 2)  {
164                                 throw new DocTagException.NO_TITLE("missing title");
165                                 return src;
166                     }
167                     
168                     //GLib.debug("nibbleTitle: regexmatches %d : %s",
169                     //           mi.get_match_count(), 
170                     //           mi.fetch(1).up());
171                     
172                     EnumClass enumc = (EnumClass) typeof (DocTagTitle).class_ref ();
173
174                     unowned EnumValue? eval = enumc.get_value_by_name ( "JSDOC_DOC_TAG_TITLE_"+  mi.fetch(1).up());
175                     if (eval == null) {
176                                 throw new DocTagException.INVALID_TITLE("title not supported ??");
177                                 return src;
178                     }
179                     this.title = (DocTagTitle) eval.value;
180                     return mi.get_match_count() > 2 ? mi.fetch(2) : "";
181
182                 }
183                  
184                   /**
185             Find and shift off the type of a tag.
186             @requires frame/String.js
187             @param {string} src
188             @return src
189          */
190         private string nibbleType(string src) 
191         {
192                     MatchInfo mi;
193             if(! /^\s*\{/.match_all(src, 0, out mi)) {
194                    return src;
195             }
196             int start;
197             int stop;
198               
199                         this.balance(src,'{', '}', out start, out stop);
200                         //GLib.debug("nibble type: %s %d, %d", src, start,stop);
201             if (stop == -1) {
202                 throw new DocTagException.INVALID_TYPE("Malformed comment tag ignored. Tag type requires an opening { and a closing }: ") ;
203                 return src;
204             }
205             this.type = src.substring(start+1,stop-1).strip();
206             this.type = this.type.replace(",", "|"); // multiples can be separated by , or |
207             return src.substring(stop+1, -1);
208             
209         }
210          
211          
212          
213         /**
214             Find and shift off the name of a tag.
215             @requires frame/String.js
216             @param {string} src
217             @return src
218          */
219                 private string nibbleName( string in_src) throws DocTagException
220         {
221
222            
223             var src = in_src.strip();
224             //GLib.debug("nibbleName: %s", in_src);
225             
226             // is optional?
227             if (src.get(0) == '[') {
228                         int start, stop;
229                  this.balance(src,'[', ']', out start, out stop);
230                 if (stop == -1) {
231                     throw new  DocTagException.INVALID_NAME("Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: ");
232                     return src;
233                 }
234                 this.name = src.substring(start+1, stop).strip();
235                 this.isOptional = true;
236                 
237                 src = src.substring(stop+1);
238                 
239                 // has default value?
240                 var nameAndValue = this.name.split("=");
241                 if (nameAndValue.length > 1) {
242                         var oname = this.name;
243                     this.name = nameAndValue[0].strip();
244
245                     this.defaultValue = oname.substring( nameAndValue[0].length + 1 , nameAndValue[0].length + 1 - oname.length); /// what about
246                 }
247                 GLib.debug("got name %s", this.name);                
248                 return src.substring(stop+1, stop+1-src.length);
249             }
250                         // not encased with [ ]
251
252                     MatchInfo mi;
253
254             if (/^(\S+)(?:\s([\s\S]*))?$/.match_full(src, src.length, 0, 0,  out mi)) {
255                         this.name = mi.fetch(1);
256                         GLib.debug("got name %s", this.name);
257                                 return mi.get_match_count() > 2 ? mi.fetch(2) : "";
258             }
259                 
260
261             return src;
262         }
263          
264          
265         private void balance(string str, char open, char close, out int start, out int stop) {
266             start = 0;
267             stop  =-1;
268             while (str.get(start) != open) {
269                 if (start == str.length) {
270                         return;
271                         }
272                 start++;
273             }
274             
275             stop = start +1;
276             var balance = 1;
277             while (stop < str.length) {
278                 if (str.get(stop) == open) balance++;
279                 if (str.get(stop) == close) balance--;
280                 if (balance == 0) break;
281                 stop++;
282                 if (stop == str.length) {
283                         stop = -1;
284                         return;
285                         }
286             }
287             
288
289                 }
290                 
291                 public Json.Array optvalue_as_json_array()
292                 {
293                         var ret = new Json.Array();
294                         foreach (var str in this.optvalues ) {
295                                 ret.add_string_element(str);
296                         }
297                         return ret;
298                         
299                         
300                 }
301                 
302         }
303 }
304         
305