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