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