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