JSDOC/TokenStream.js
[gnome.introspection-doc-generator] / JSDOC / TokenStream.js
1 //<script type="text/javscript">
2
3
4 XObject = imports.XObject.XObject;
5  
6
7
8 console = imports.console.console;
9 Token   = imports.Token.Token;
10 Lang    = imports.Lang.Lang;
11
12
13 /**
14  * @class TokenStream
15  * 
16  * BC notes:
17  * 
18  * nextT => nextTok
19  * lookT => lookTok
20  * 
21  */
22         
23  
24 TokenStream = XObject.define(
25
26     /**
27      * @constructor
28      * 
29      * 
30      */
31
32     function(tokens) {
33      
34         
35         this.tokens = (tokens || []);
36        // Seed.print(this.tokens.length);
37         this.rewind();
38     },
39     Object,
40     {
41         cursor : -1, // where are we in the stream.
42         
43         rewind : function() {
44             this.cursor = -1;
45         },
46
47         /**
48             @type JSDOC.Token
49         */
50         look : function(/**Number*/n, /**Boolean*/considerWhitespace) {
51             if (typeof n == "undefined") n = 0;
52
53             if (considerWhitespace == true) {
54                 if (this.cursor+n < 0 || this.cursor+n > (this.tokens.length -1)) {
55                     return new Token("", "VOID", "START_OF_STREAM");
56                 }
57                 return this.tokens[this.cursor+n];
58             }
59             else {
60                 var count = 0;
61                 var i = this.cursor;
62
63                 while (true) {
64                     if (i < 0) return new Token("", "VOID", "START_OF_STREAM");
65                     else if (i > this.tokens.length) return new Token("", "VOID", "END_OF_STREAM");
66
67                     if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT"))) {
68                         if (n < 0) i--; else i++;
69                         continue;
70                     }
71                     
72                     if (count == Math.abs(n)) {
73                         return this.tokens[i];
74                     }
75                     count++;
76                     (n < 0)? i-- : i++;
77                 }
78
79                 return new Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object
80             }
81         },
82
83         lookFor : function (data)
84         {
85             // non tree version..
86             var i = this.cursor < 0 ? 0 : this.cursor ;
87             
88             while (true) {
89                 if (i >= this.tokens.length) return -1;
90                 if (this.tokens[i].data == data) {
91                     return i;
92                 }
93                 i++;
94                 
95             }
96             // should not get here!
97             return -1;
98
99         },
100
101
102         /**
103          * look ahead (or back) x number of tokens (which are not comment or whitespace)
104          * ?? used any more?
105          */
106         lookTok : function(/**Number*/n) {
107             if (typeof n == "undefined") n = 1;
108
109             
110             var count = 0;
111             var i = this.cursor;
112
113             while (true) {
114                // print(i);
115                 if (i < 0) {
116                     if (n > -1) {
117                         i = 0; continue;
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             @type JSDOC.Token|JSDOC.Token[]| null!
141         */
142         next : function(/**Number*/howMany) {
143             if (typeof howMany == "undefined") howMany = 1;
144             if (howMany < 1) return null;
145             var got = [];
146
147             for (var i = 1; i <= howMany; i++) {
148                 if (this.cursor+i >= this.tokens.length) {
149                     return null;
150                 }
151                 got.push(this.tokens[this.cursor+i]);
152             }
153             this.cursor += howMany;
154
155             if (howMany == 1) {
156                 return got[0];
157             }
158             else return got;
159         },
160         // what about comments after 'function'...
161         // is this used ???
162         nextTok  : function() {
163             return this.nextNonSpace();
164         },
165         nextNonSpace : function ()
166         {
167             
168             while (true) {
169                 tok = this.next(1);
170                 if (!tok) {
171                     return false;
172                 }
173                 if (tok.is('WHIT') ||  tok.is('COMM')) {
174                     continue;
175                 }
176                 return tok;
177             }
178         },
179         /**
180          *    @type JSDOC.Token[]
181          * @param start {String}  token name or data (eg. '{'
182          * @param stop {String} (Optional) token name or data (eg. '}'
183          */
184         balance : function(/**String*/start, /**String*/stop) {
185             
186             start = typeof(Lang.matching(start)) == 'undefined' ? Lang.punc(start) : start;
187             
188             if (!stop) stop = Lang.matching(start);
189             
190             var depth = 0;
191             var got = [];
192             var started = false;
193             //Seed.print("STOP:" + stop);
194             while ((token = this.look())) {
195                 if (token.is(start)) {
196                     depth++;
197                     started = true;
198                 }
199                 
200                 if (started) {
201                     got.push(token);
202                 }
203                 
204                 if (token.is(stop)) {
205                     depth--;
206                     if (depth == 0) return got;
207                 }
208                 if (!this.next()) break;
209             }
210         },
211
212         getMatchingToken : function(/**String*/start, /**String*/stop) {
213             var depth = 0;
214             var cursor = this.cursor;
215             
216             if (!start) {
217                 start = Lang.matching(stop);
218                 depth = 1;
219             }
220             if (!stop) stop = Lang.matching(start);
221             
222             while ((token = this.tokens[cursor])) {
223                 if (token.is(start)) {
224                     depth++;
225                 }
226                 
227                 if (token.is(stop) && cursor) {
228                     depth--;
229                     if (depth == 0) return this.tokens[cursor];
230                 }
231                 cursor++;
232             }
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()
260         {
261             this.tokens.forEach(function(t) {
262                 print(t.toString());
263             });
264         }
265 });
266