/** * * base class for parsing segments of token array.. * * * We want to make parsing the whole thing easy.. * * so we do various tricks: * * * a) white space collased * wsPrefix * b) toks * { } - collapse into first element. ( ) - collapse into first element. [ ] - collapse into first element. * c) items = , seperation within the above.. * * usage: x = new Collapse(token_array) * * * * */ namespace JSDOC { public class Collapse : TokenStream { public Collapse(Gee.ArrayList tokens) { base(tokens); this.spaces(); var ar = this.collapse(this.tokens); this.tokens = ar; // console.dump(ar); } // put spaces into prefix of tokens.. void spaces () { var ar = new Gee.ArrayList(); var pref = new Gee.ArrayList(); for (var i = 0; i < this.tokens.size; i ++) { var tok = this.tokens[i]; if (tok.is("COMM") || tok.is("WHIT")) { pref.add(tok); continue; } tok.prefix = ""; if (pref.size > 0) { foreach(var e in pref) { tok.prefix += e.data; } pref = new Gee.ArrayList(); // reset pref.. } ar.add(tok); } this.tokens = ar; } Gee.ArrayList collapse(Gee.ArrayList ar) { var st = new TokenStream(ar); var ret = new Gee.ArrayList(); while (true) { var tok = st.look(1,true); if (tok == null) { // Seed.print(TokenStream.toString(ret)); return ret; } // console.log(tok.data); debug("COL: %s", tok.asString()); switch(tok.type) { case "VOID": return ret; //EOF case "KEYW": case "TOKN": case "NAME": case "STRN": case "NUMB": case "REGX": var nn = st.next(); if (nn != null) { ret.add(nn); } continue; case "PUNC": switch (tok.data) { case "[": case "{": case "(": var start = st.cursor; //st.next(); << no need to shift, balance will start at first character.. var add = st.balance(tok.data); debug("BALANCE returned %d items\n", add.size); // if (!add) { //console.dump(tok); //console.dump(start + '...' + st.cursor); //console.dump(st.tokens); //} if (add.size > 0) { add.remove_at(0); // remove the first element... (as it's the } //Seed.print("ADD"); //Seed.print(JSON.stringify(add, null,4)); var toks = add.size > 0 ? this.collapse(add) : add; tok.items = new Gee.ArrayList>(); //?? needed? tok.props = new Gee.HashMap(); if (tok.data != "{") { // paramters or array elements.. tok.items = this.toItems(toks, ","); } else { // check for types.. it could be a list of statements.. or object // format "{" "xXXX" ":" << looks for the ':'.. seems to work.. not sure if it's foolproof... var ost = new TokenStream(toks); //console.dump(ost.look(2,true) ); if (ost.look(2,true) != null && ost.look(2,true).data == ":") { // object properties... tok.props = this.toProps(toks); } else { // list of statemetns.. tok.items = this.toItems(toks, ";{");; } } //Seed.print(" ADD : " + add.length + " ITEMS: " + tok.items.length); ret.add(tok); continue; default: ret.add(st.next()); continue; } print("OOPS"); continue; default : print("OOPS" + tok.type); continue; } } } // array of arrays of tokens Gee.ArrayList> toItems(Gee.ArrayList ar, string sep) { var ret = new Gee.ArrayList>() ; var g = new Gee.ArrayList() ; for (var i = 0; i < ar.size; i ++) { if (sep.index_of(ar.get(i).data) < 0) { g.add(ar.get(i)); continue; } // var a=..., b =... if ((ar.get(i).data != ";") && g.size> 0 && (g[0].name == "VAR")) {; g.add(ar.get(i)); continue; } g.add(ar.get(i)); ret.add(g); g = new Gee.ArrayList() ; } // last.. if (g.size > 0) { ret.add(g); } return ret; } Gee.HashMap toProps (Gee.ArrayList ar) { var ret = new Gee.HashMap(); var g = new TokenKeyMap(); var k = ""; var state = 0; for (var i = 0; i < ar.size; i ++) { switch(state) { case 0: k = ar.get(i).data; g.key = ar.get(i); state = 1; continue; case 1: state =2; // should be ':' continue; case 2: g.vals.add( ar.get(i)); if ( ar.get(i).data != ",") { continue; } ret.set(k, g); g = new TokenKeyMap(); state = 0; continue; } } // last.. - if g.val.length is 0 then it's a trailing ','... // we should really throw a syntax error in that case.. if (k.length > 0 && g.vals.size > 0) { ret.set(k, g); } return ret; } } }