JSDOC/TokenReader.js
[gnome.introspection-doc-generator] / JSDOC / DocTag.js
1 //<script  type="text/javascript">
2  
3  
4 XObject = imports.XObject.XObject;
5
6 Options = imports.Options.Options;
7
8  
9 /**
10  * DocTag - represents a single A=b tag.
11  * @class DocTag
12  */
13  
14  
15 DocTag = XObject.define(
16
17 /**
18  * @constructor
19  * @arg {String} src
20  */
21
22     function(src) {
23         this.title        = "";
24         this.type         = "";
25         this.name         = "";
26         this.isOptional   = false;
27         this.defaultValue = "";
28         this.desc         = "";
29         this.optvalues    = false;
30         if (typeof src != "undefined") {
31             this.parse(src);
32         }
33     }, 
34     Object,
35     {
36         
37         title: '',
38         type: '',
39         name : '',
40         isOptional : false,
41         defaultValue : '',
42         desc : '',
43         /**
44          * serialize..
45          */
46         toJSON :function(t)
47         {
48             var ret = { '*object' : 'DocTag' };
49             
50             for (var i in this) {
51                 if (i == 'optvalues') { 
52                     ret[i] = this.optvalues;
53                     continue;
54                 }
55                 
56                 switch (typeof(this[i])) {
57                     case 'function':
58                        continue;
59                        continue;
60                         
61                     case 'string':
62                     case 'number':
63                     case 'boolean':                    
64                         ret[i] = this[i]; continue;
65                         
66                         
67                         
68                     default:
69                         
70                         print("unknown type: (" + i + ")"  + typeof(this[i]));
71                         this.toJSON = null;
72                         print(JSON.stringify(this));;
73                         Seed.quit();
74                    }
75             }
76             return ret;
77         },
78         
79
80
81         /**
82             Populate the properties of this from the given tag src.
83             @param {string} src
84          */
85         parse : function(src) {
86             if (typeof src != "string") throw "src must be a string not "+(typeof src);
87
88             try {
89                 src = this.nibbleTitle(src);
90                 //if (JSDOC.PluginManager) {
91                 //    JSDOC.PluginManager.run("onDocTagSynonym", this);
92                // }
93                 
94                 src = this.nibbleType(src);
95                 
96                 // only some tags are allowed to have names.
97                 if (this.title == "param" || this.title == "property" || this.title == "cfg") { // @config is deprecated
98                     src = this.nibbleName(src);
99                 }
100             }
101             catch(e) {
102                 if (Options.LOG) Options.LOG.warn(e);
103                 else throw e;
104             }
105             
106             // if type == @cfg, and matches (|....|...)
107             
108             src = src.trim();
109             if (this.title == "cfg" && src.match(/^\([^)]+\)/)) {
110                 var m = src.match(/^\(([^)]+)\)/);
111                 print(m);
112                 if (m[1].match(/\|/)) {
113                     var opts = m[1].trim().split(/\s*\|\s*/);
114                     this.optvalues = opts;
115                     src = src.substring(m[0].length).trim();
116                     print(src);
117                     
118                     
119                 }
120                 
121                 
122             }
123             
124             
125             this.desc = src; // whatever is left
126             
127             // example tags need to have whitespace preserved
128             if (this.title != "example") this.desc = this.desc.trim();
129             
130             //if (JSDOC.PluginManager) {
131             //    JSDOC.PluginManager.run("onDocTag", this);
132             //}
133         },
134
135         /**
136             Automatically called when this is stringified.
137          */
138         toString : function() {
139             return this.desc;
140         },
141          
142
143         /**
144             Find and shift off the title of a tag.
145             @param {string} src
146             @return src
147          */
148         nibbleTitle : function(src) {
149             if (typeof src != "string") throw "src must be a string not "+(typeof src);
150             
151             var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
152
153             if (parts && parts[1]) this.title = parts[1];
154             if (parts && parts[2]) src = parts[2];
155             else src = "";
156             
157             return src;
158         },
159          
160         /**
161             Find and shift off the type of a tag.
162             @requires frame/String.js
163             @param {string} src
164             @return src
165          */
166         nibbleType : function(src) 
167         {
168             if (typeof src != "string") throw "src must be a string not "+(typeof src);
169             
170             if (src.match(/^\s*\{/)) {
171                 var typeRange = this.balance(src,"{", "}");
172                 if (typeRange[1] == -1) {
173                     throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
174                 }
175                 this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
176                 this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
177                 src = src.substring(typeRange[1]+1);
178             }
179             
180             return src;
181         },
182          
183
184         /**
185             Find and shift off the name of a tag.
186             @requires frame/String.js
187             @param {string} src
188             @return src
189          */
190         nibbleName : function(src) {
191             if (typeof src != "string") throw "src must be a string not "+(typeof src);
192             
193             src = src.trim();
194             
195             // is optional?
196             if (src.charAt(0) == "[") {
197                 var nameRange = this.balance(src,"[", "]");
198                 if (nameRange[1] == -1) {
199                     throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
200                 }
201                 this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
202                 this.isOptional = true;
203                 
204                 src = src.substring(nameRange[1]+1);
205                 
206                 // has default value?
207                 var nameAndValue = this.name.split("=");
208                 if (nameAndValue.length) {
209                     this.name = nameAndValue.shift().trim();
210                     this.defaultValue = nameAndValue.join("=");
211                 }
212             }
213             else {
214                 var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
215                 if (parts) {
216                     if (parts[1]) this.name = parts[1];
217                     if (parts[2]) src = parts[2].trim();
218                     else src = "";
219                 }
220             }   
221
222             return src;
223         },
224         
225         balance : function(str, open, close) {
226             var i = 0;
227             while (str.charAt(i) != open) {
228                 if (i == str.length) return [-1, -1];
229                 i++;
230             }
231             
232             var j = i+1;
233             var balance = 1;
234             while (j < str.length) {
235                 if (str.charAt(j) == open) balance++;
236                 if (str.charAt(j) == close) balance--;
237                 if (balance == 0) break;
238                 j++;
239                 if (j == str.length) return [-1, -1];
240             }
241             
242             return [i, j];
243 }
244
245         
246         
247 });
248
249 // cached support?
250 DocTag.fromDump = function(t)
251 {
252     var ns = new DocTag();
253     for (var i in t) {
254         if (typeof(ns[i]) == "undefined") {
255             println("ERR:no default for DocTag:"+ i);
256         }
257        ns[i] = t[i];
258     }
259     return ns;
260 }