/** * @class TokenStream * * BC notes: * * nextT => nextTok * lookT => lookTok * */ namespace JSDOC { public class TokenStream : Object { Gee.ArrayList tokens; int cursor; // where are we in the stream. public TokenStream(Gee.ArrayList tokens) { this.tokens = tokens; this.rewind(); } public void rewind() { this.cursor = -1; } /** @type JSDOC.Token */ public Token? look (int n, bool considerWhitespace) { if (considerWhitespace == true) { if (this.cursor+n < 0 || this.cursor+n > (this.tokens.size -1)) { return new Token("", "VOID", "START_OF_STREAM"); } return this.tokens.get(this.cursor+n); } var count = 0; var i = this.cursor; while (true) { if (i < 0) { return new Token("", "VOID", "START_OF_STREAM"); } if (i > this.tokens.size) { return new Token("", "VOID", "END_OF_STREAM"); } if (i != this.cursor && this.tokens.get(i).is("WHIT")) { i += (n < 0) ? -1 : 1; continue; } if (count == n) { return this.tokens.get(i); } count++; i += (n < 0) ? -1 : 1; } return new Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object } public int lookFor (string data) { // non tree version.. var i = this.cursor < 0 ? 0 : this.cursor ; while (true) { if (i >= this.tokens.size) { return -1; } if (this.tokens.get(i).data == data) { return i; } i++; } // should not get here! return -1; } /** * look ahead (or back) x number of tokens (which are not comment or whitespace) * ?? used any more? */ public Token lookTok (int n) { var count = 0; var i = this.cursor; while (true) { // print(i); if (i < 0) { if (n > -1) { i = 0; count++; continue; } return new Token("", "VOID", "END_OF_STREAM"); } if (i > this.tokens.length) { return new Token("", "VOID", "END_OF_STREAM"); } if (i != this.cursor && ( this.tokens.get(i).is("WHIT") || this.tokens.get(i).is("COMM"))) { i += (n < 0) ? -1 : 1; continue; } if (count == n) { return this.tokens.get(i); } count++; i += (n < 0) ? -1 : 1; } // should never get here.. return new Token("", "VOID", "END_OF_STREAM");; // because null isn't an object and caller always expects an object; } /** * @return {Token|null} * next token (with white space) */ public Token next(int howMany) { //if (typeof howMany == "undefined") howMany = 1; if (howMany < 1) { return null; } var got = []; for (var i = 1; i <= howMany; i++) { if (this.cursor+i >= this.tokens.length) { return null; } got.push(this.tokens[this.cursor+i]); } this.cursor += howMany; if (howMany == 1) { return got[0]; } else return got; }, // what about comments after 'function'... // is this used ??? nextTok : function() { return this.nextNonSpace(); }, nextNonSpace : function () { while (true) { tok = this.next(1); if (!tok) { return false; } if (tok.is('WHIT') || tok.is('COMM')) { continue; } return tok; } }, /** * @type JSDOC.Token[] * @param start {String} token name or data (eg. '{' * @param stop {String} (Optional) token name or data (eg. '}' */ balance : function(/**String*/start, /**String*/stop) { start = typeof(Lang.punc(start)) == 'undefined' ? start : Lang.punc(start); if (!stop) stop = Lang.matching(start); var depth = 0; var got = []; var started = false; //Seed.print("START:" + start); //Seed.print("STOP:" + stop); while ((token = this.look())) { if (token.is(start)) { // Seed.print("balance: START : " + depth + " " + token.data); depth++; started = true; } if (started) { got.push(token); } if (token.is(stop)) { depth--; // Seed.print("balance: STOP: " + depth + " " + token.data); if (depth < 1) return got; } if (!this.next()) break; } return false; }, getMatchingToken : function(/**String*/start, /**String*/stop) { var depth = 0; var cursor = this.cursor; if (!start) { start = Lang.matching(stop); depth = 1; } if (!stop) stop = Lang.matching(start); while ((token = this.tokens[cursor])) { if (token.is(start)) { depth++; } if (token.is(stop) && cursor) { depth--; if (depth == 0) return this.tokens[cursor]; } cursor++; } return false; }, insertAhead : function(/**JSDOC.Token*/token) { this.tokens.splice(this.cursor+1, 0, token); }, remaining : function() { var ret = []; while (true) { var tok = this.look(1,true); if (!tok || !tok.is || tok.is('VOID')) { return ret; } ret.push(this.next(1)); } }, arrayToString : function(ar) { console.log(typeof(ar)); var ret = []; ar.forEach(function(e) { ret.push(e.data); }) return ret.join(''); }, dump: function(start, end) { start = Math.max(start || 0, 0); end = Math.min(end || this.tokens.length, this.tokens.length); var out=''; for (var i =start;i < end; i++) { out += (this.tokens[i].outData == false) ? this.tokens[i].data : this.tokens[i].outData; }; print(out); } });