JSDOC/TokenStream.vala
[gnome.introspection-doc-generator] / JSDOC / TokenStream.vala
1
2 /**
3  * @class TokenStream
4  * 
5  * BC notes:
6  * 
7  * nextT => nextTok
8  * lookT => lookTok
9  * 
10  */
11         
12
13 namespace JSDOC {
14
15         class TokenStream : Object
16
17                 Gee.ArrayList<Token> tokens;
18                 
19                 
20                 
21                 TokenStream(Gee.ArrayList<Token> tokens) {
22                  
23                     this.tokens = tokens;
24
25                     this.rewind();
26                 }
27                 
28                     int cursor; // where are we in the stream.
29                     
30                     void rewind() {
31                         this.cursor = -1;
32                     }
33
34                     /**
35                         @type JSDOC.Token
36                     */
37                     look : function(int n, bool considerWhitespace) 
38                     {
39                         if (typeof n == "undefined") n = 0;
40
41                         if (considerWhitespace == true) {
42                             if (this.cursor+n < 0 || this.cursor+n > (this.tokens.length -1)) {
43                                 return new Token("", "VOID", "START_OF_STREAM");
44                             }
45                             return this.tokens[this.cursor+n];
46                         }
47                         else {
48                             var count = 0;
49                             var i = this.cursor;
50
51                             while (true) {
52                                 if (i < 0) return new Token("", "VOID", "START_OF_STREAM");
53                                 else if (i > this.tokens.length) return new Token("", "VOID", "END_OF_STREAM");
54
55                                 if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT"))) {
56                                     if (n < 0) i--; else i++;
57                                     continue;
58                                 }
59                                 
60                                 if (count == Math.abs(n)) {
61                                     return this.tokens[i];
62                                 }
63                                 count++;
64                                 (n < 0)? i-- : i++;
65                             }
66
67                             return new Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object
68                         }
69                     },
70
71                     lookFor : function (data)
72                     {
73                         // non tree version..
74                         var i = this.cursor < 0 ? 0 : this.cursor ;
75                         
76                         while (true) {
77                             if (i >= this.tokens.length) return -1;
78                             if (this.tokens[i].data == data) {
79                                 return i;
80                             }
81                             i++;
82                             
83                         }
84                         // should not get here!
85                         return -1;
86
87                     },
88
89
90                     /**
91                      * look ahead (or back) x number of tokens (which are not comment or whitespace)
92                      * ?? used any more?
93                      */
94                     lookTok : function(/**Number*/n) {
95                         if (typeof n == "undefined") n = 1;
96
97                         
98                         var count = 0;
99                         var i = this.cursor;
100
101                         while (true) {
102                            // print(i);
103                             if (i < 0) {
104                                 if (n > -1) {
105                                     i = 0; 
106                                     count++;
107                                     continue;
108                                     
109                                 }
110                                 return   new Token("", "VOID", "END_OF_STREAM");
111                             }
112                             else if (i > this.tokens.length) return  new Token("", "VOID", "END_OF_STREAM");
113
114                             if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT") || this.tokens[i].is("COMM"))) {
115                                 if (n < 0) i--; else i++;
116                                 continue;
117                             }
118                             
119                             if (count == Math.abs(n)) {
120                                 return this.tokens[i];
121                             }
122                             count++;
123                             (n < 0)? i-- : i++;
124                         }
125                     // should never get here..
126                         return false; // because null isn't an object and caller always expects an object;
127                         
128                     },
129
130                     /**
131                      *  @return {Token|null}
132                      * next token (with white space)
133                      */
134                         
135                        
136                     next : function(/**Number*/howMany) {
137                         if (typeof howMany == "undefined") howMany = 1;
138                         if (howMany < 1) return null;
139                         var got = [];
140
141                         for (var i = 1; i <= howMany; i++) {
142                             if (this.cursor+i >= this.tokens.length) {
143                                 return null;
144                             }
145                             got.push(this.tokens[this.cursor+i]);
146                         }
147                         this.cursor += howMany;
148
149                         if (howMany == 1) {
150                             return got[0];
151                         }
152                         else return got;
153                     },
154                     // what about comments after 'function'...
155                     // is this used ???
156                     nextTok  : function() {
157                         return this.nextNonSpace();
158                     },
159                     nextNonSpace : function ()
160                     {
161                         
162                         while (true) {
163                             tok = this.next(1);
164                             if (!tok) {
165                                 return false;
166                             }
167                             if (tok.is('WHIT') ||  tok.is('COMM')) {
168                                 continue;
169                             }
170                             return tok;
171                         }
172                     },
173                     /**
174                      *    @type JSDOC.Token[]
175                      * @param start {String}  token name or data (eg. '{'
176                      * @param stop {String} (Optional) token name or data (eg. '}'
177                      */
178                     balance : function(/**String*/start, /**String*/stop) {
179                         
180                         
181                         start = typeof(Lang.punc(start)) == 'undefined' ? start : Lang.punc(start);
182                         
183                         if (!stop) stop = Lang.matching(start);
184                         
185                         var depth = 0;
186                         var got = [];
187                         var started = false;
188                         //Seed.print("START:" + start);
189                         //Seed.print("STOP:" + stop);
190                         while ((token = this.look())) {
191                             if (token.is(start)) {
192                           //      Seed.print("balance: START : " + depth + " " + token.data);
193                                 depth++;
194                                 started = true;
195                             }
196                             
197                             if (started) {
198                                 got.push(token);
199                             }
200                             
201                             if (token.is(stop)) {
202                                 depth--;
203                             //    Seed.print("balance: STOP: "  + depth + " " + token.data);
204                                 if (depth < 1) return got;
205                             }
206                             if (!this.next()) break;
207                         }
208                         return false;
209                     },
210
211                     getMatchingToken : function(/**String*/start, /**String*/stop) {
212                         var depth = 0;
213                         var cursor = this.cursor;
214                         
215                         if (!start) {
216                             start = Lang.matching(stop);
217                             depth = 1;
218                         }
219                         if (!stop) stop = Lang.matching(start);
220                         
221                         while ((token = this.tokens[cursor])) {
222                             if (token.is(start)) {
223                                 depth++;
224                             }
225                             
226                             if (token.is(stop) && cursor) {
227                                 depth--;
228                                 if (depth == 0) return this.tokens[cursor];
229                             }
230                             cursor++;
231                         }
232                         return false;
233                     },
234
235                     insertAhead : function(/**JSDOC.Token*/token) {
236                         this.tokens.splice(this.cursor+1, 0, token);
237                     },
238                      
239                     remaining : function() {
240                         var ret = [];
241                         while (true) {
242                             var tok = this.look(1,true);
243                             if (!tok || !tok.is || tok.is('VOID')) {
244                                 return ret;
245                             }
246                             ret.push(this.next(1));
247                         }
248                     },
249                      
250
251                     arrayToString : function(ar) {
252                         console.log(typeof(ar));
253                         var ret = [];
254                         ar.forEach(function(e) {
255                             ret.push(e.data);
256                         })
257                         return ret.join('');
258                     },
259                     dump: function(start, end)
260                     {
261                         start = Math.max(start || 0, 0);
262                         end = Math.min(end || this.tokens.length, this.tokens.length);
263                         var out='';
264                         for (var i =start;i < end; i++) {
265                             
266                             out += (this.tokens[i].outData == false) ? this.tokens[i].data : this.tokens[i].outData;
267                         };
268                         print(out);
269                     }
270         });
271