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