001package gudusoft.gsqlparser;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005
006/**
007 * List of source token.
008 */
009public class TSourceTokenList implements Iterator<TSourceToken>  {
010    public void set(int index, TSourceToken st) {
011       // st.setGsqlparser(this.gsqlparser);
012        items.set(index, st);
013    }
014
015    int iteratorpos = -1;
016
017    public TGSqlParser getGsqlparser() {
018        return gsqlparser;
019    }
020
021    public void setGsqlparser(TGSqlParser gsqlparser) {
022
023        this.gsqlparser = gsqlparser;
024    }
025
026    private TGSqlParser gsqlparser = null;
027
028    public void resetiterator(){
029        iteratorpos = -1;
030    }
031
032    public boolean hasNext(){
033       boolean ret = (iteratorpos < (items.size() - 1));
034       if (ret) iteratorpos++;
035       return ret;
036    }
037    
038    public TSourceToken next(){
039       return (TSourceToken)items.get(iteratorpos) ;
040    }
041
042    /**
043     * Not supportted yet.
044     */
045    public void remove(){
046     throw new UnsupportedOperationException();
047    }
048
049    public TSourceTokenList(){
050        items = new ArrayList();
051        curpos = -1;
052        resetiterator();
053    }
054    ArrayList items;
055
056    /**
057     * Used by parser internally.
058     * this curpos is start from -1, when a new token is created, curpos must be increased by 1 and then assign this
059     * value to the  {@link  TSourceToken.posinlist} .
060     */
061    int curpos;
062    
063    public TSourceToken get(int index){
064        return  (TSourceToken)items.get(index);
065    }
066
067    public void add(TSourceToken st){
068       // st.setGsqlparser(this.gsqlparser);
069        items.add(st);
070    }
071
072    public void add(int index,TSourceToken st){
073        //st.setGsqlparser(this.gsqlparser);
074        items.add(index,st);
075    }
076
077    public void remove(int index){
078        items.remove(index);
079    }
080
081    public void remove(TSourceToken st){
082        items.remove(st);
083    }
084
085    public int size(){
086        return items.size();
087    }
088
089    public void clear(){
090        items.clear();
091    }
092
093
094    boolean isnonsolidtoken(TSourceToken st,boolean pcmtissolidtoken){
095        boolean ret = false;
096        switch(st.tokentype){
097            case ttwhitespace:
098            case ttreturn:
099                ret = true;
100                break;
101            case ttsimplecomment:
102            case ttbracketedcomment:
103                if (!pcmtissolidtoken) ret = true;
104                break;
105        }
106        return ret;
107    }
108
109    /**
110     * Find solid token start from ptoken, distance is pstep. 
111     * @param ptoken  Search start from this token. 
112     * @param pstep  If pstep &gt; 0 then find solid token after ptoken, if pstep &lt; 0 then find solid token before ptoken.
113     * @param pcmtissolidtoken If it's true then treat comment as solid token.
114     * @return
115     */
116    public TSourceToken nextsolidtoken(TSourceToken ptoken,int pstep,boolean pcmtissolidtoken){
117       TSourceToken ret = null;
118       if (ptoken == null) {return null;}
119       if (ptoken.posinlist == -1) {return null;};
120       return nextsolidtoken(ptoken.posinlist,pstep,pcmtissolidtoken);
121    }
122
123    /**
124     * Find solid token start from ptoken, distance is pstep.
125     * @param ptokenpos Search start from this position, not include this token
126     * @param pstep If pstep &gt; 0 then find solid token after ptoken, if pstep &lt; 0 then find solid token before ptoken.
127     * @param pcmtissolidtoken  If it's true then treat comment as solid token.
128     * @return
129     */
130    public TSourceToken nextsolidtoken(int ptokenpos,int pstep,boolean pcmtissolidtoken){
131        TSourceToken ret = null;
132        if (items == null) {return ret;}
133
134        if (ptokenpos < 0 )  {return ret;}
135        if (ptokenpos > size() - 1) {return ret;}
136        if ((pstep > 0) && (ptokenpos == size() - 1)) {return ret;}
137
138        //lcnonsolidtokenset := [ttwhitespace,ttreturn];
139        if (!pcmtissolidtoken)
140        {
141            //lcnonsolidtokenset = lcnonsolidtokenset + [ttsimplecomment,ttbracketedcomment];
142        }
143
144        int step = 0;
145        if (pstep > 0 )
146        for (int i= ptokenpos + 1; i < size();i++)
147        {
148            TSourceToken lctoken = this.get(i);
149            if (isnonsolidtoken(lctoken,pcmtissolidtoken))
150            {
151                 continue;
152            }
153            step++;
154            if (step == pstep)
155            {
156                ret = this.get(i);
157                break;
158            }
159        }
160
161        if (pstep < 0 )
162        {
163             
164        for (int i= ptokenpos - 1; i >= 0;i--)
165        {
166           TSourceToken lctoken = this.get(i);
167            if (isnonsolidtoken(lctoken,pcmtissolidtoken))
168            {
169                 continue;
170            }
171            step++;
172            if (step == Math.abs(pstep))
173            {
174                ret = this.get(i);
175                break;
176            }
177        }
178        }
179        return ret;
180    }
181
182    /**
183     * Search token of the next/previous object
184     *
185     * @param ptokenpos, search from this token, not included.
186     * @param pstep  pstep &gt; 0 means search forward, &lt;0 means search backward
187     * @param pcmtissolidtoken, treat comment as solid token if it's true.
188     * @return -1 means not found. If search next, then return position of the last token of qualified object name,
189     * if search previous, then return position of the first token of qualified object name.
190     */
191    public int nextObjectNameToken(int ptokenpos,int pstep,boolean pcmtissolidtoken){
192        int ret = -1;
193        boolean waitForNextSolidToken = false;
194        if (items == null) {return ret;}
195
196        if (ptokenpos < 0 )  {return ret;}
197        if (ptokenpos > size() - 1) {return ret;}
198        if ((pstep > 0) && (ptokenpos == size() - 1)) {return ret;}
199
200        int step = 0;
201        if (pstep > 0 )
202            for (int i= ptokenpos + 1; i < size();i++)
203            {
204                TSourceToken lctoken = this.get(i);
205                if (isnonsolidtoken(lctoken,pcmtissolidtoken))
206                {
207                    continue;
208                }
209                if (lctoken.tokencode == '.') {
210                    waitForNextSolidToken = true;
211                    continue;
212                }
213
214                if (ret == -1){
215                    ret = i;
216                    continue;
217                }else{
218                    if (waitForNextSolidToken){
219                        waitForNextSolidToken = false;
220                        ret = i;
221                        continue;
222                    }
223                }
224
225                step++;
226                if (step == pstep) break;
227            }
228
229        if (pstep < 0 )
230        {
231
232            for (int i= ptokenpos - 1; i >= 0;i--)
233            {
234                TSourceToken lctoken = this.get(i);
235                if (isnonsolidtoken(lctoken,pcmtissolidtoken))
236                {
237                    continue;
238                }
239
240                if (lctoken.tokencode == '.') {
241                    waitForNextSolidToken = true;
242                    continue;
243                }
244
245                if (ret == -1){
246                    ret = i;
247                    continue;
248                }else{
249                    if (waitForNextSolidToken){
250                        waitForNextSolidToken = false;
251                        ret = i;
252                        continue;
253                    }
254                }
255
256                step++;
257                if (step == Math.abs(pstep)) break;
258            }
259        }
260        return ret;
261    }
262
263  int solidtokenafterpos(int piindex,String psstr,int scope,String ignoretoken){
264      int ret = 0;
265      if ( items == null ) return ret;
266
267      if ( piindex < 0 ) return ret;
268      if ( piindex > size() - 2 ) return ret;
269      int step = 0;
270      for (int i = piindex + 1; i< size() ;i++)
271        {
272          if (this.get(i).isnonsolidtoken()) continue;
273
274          if ( (ignoretoken.length() > 0) && ( TBaseType.mycomparetext(this.get(i).astext,ignoretoken) == 0) ) continue;
275
276          if ( TBaseType.mycomparetext(psstr,this.get(i).astext) == 0 ) ret = i;
277          step++;
278          if ( (ret > 0) || (step >= scope) )
279            break;
280        };
281   return ret;
282  }
283
284    /**
285     * Search token by token code, start from pStart within range pSteps, and ignore pIngoreThisString if any during searching.
286     * Ingore non-solid token while searching.
287     * 
288     * @param pStart Start from this position. 
289     * @param pTokenCode TokenCode that search for.
290     * @param pSteps Must &gt; 0.
291     * @param pIgnoreThisString String to be ignored.
292     * @return 0 if no token found, otherwise, return position in sourcetoken list.
293     */
294    public int solidtokenafterpos(int pStart,int pTokenCode,int pSteps,String pIgnoreThisString){
295        int ret = 0;
296        if ( items == null ) return ret;
297
298        if ( pStart < 0 ) return ret;
299        if ( pStart > size() - 2 ) return ret;
300        int step = 0;
301        for (int i = pStart + 1; i< size() ;i++)
302          {
303            if (this.get(i).isnonsolidtoken()) continue;
304            if ( (pIgnoreThisString.length() > 0) && ( TBaseType.mycomparetext(this.get(i).astext,pIgnoreThisString) == 0) ) continue;
305
306
307            if ( pTokenCode == this.get(i).tokencode ) ret = i;
308            step++;
309            if ( (ret > 0) || (step >= pSteps) )
310              break;
311          };
312     return ret;
313    }
314
315    /**
316     * Search solid token before pStart.
317     * @param pStart
318     * @return return null if no token found.
319     */
320 public TSourceToken solidtokenbefore(int pStart){
321     return nextsolidtoken(pStart,-1,false);
322 }
323
324public boolean sqlplusaftercurtoken(){
325    return  (sqlplusaftertoken(curpos) > 0);
326}
327
328    /**
329     * Search Oracle sqlplus token after pStart. Ignore non-solid token while searching. 
330     * @param pStart
331     * @return
332     */
333int sqlplusaftertoken(int pStart){
334    int ret = 0;
335    if (items == null) return ret;
336
337    if ((pStart < 0 ) || (pStart+1 > size() - 1 ))  return ret;
338    for (int i = pStart+1;i <size();i++)
339    {
340        if (this.get(i).isnonsolidtoken()) continue;
341        if (get(i).tokencode == TBaseType.sqlpluscmd) ret = i;
342        break;
343    }
344
345    return ret;
346}
347
348 public  int searchLastTokenAtTheSameLine(int pStart){
349        int ret = -1;
350        if (items == null) return ret;
351
352        if ((pStart < 0 ) || (pStart+1 > size() - 1 ) ) return ret;
353        for (int i = pStart+1; i<size();i++)
354        {
355            ret = i;
356            if (get(i).tokentype == ETokenType.ttreturn) break;
357        }
358
359        return ret-1;
360    }
361
362    /**
363     * Is there linebreak after current token.
364     * @param ignorecmt If it's true, ignore comment while searching linebreak.
365     * @return
366     */
367public boolean returnaftercurtoken(boolean ignorecmt){
368  return searchReturnTokenDirectlyAfter(curpos,ignorecmt) > 0;
369}
370
371    /**
372     *  Found whether a linebreak is followed directly after the start token,
373     *  If linebreak is followed directly, return the position of this linebreak, otherwise, return 0
374     *
375     * @param pStart Start from this position in sourcetoken list.
376     * @param ignorecomment If it's true, ignore comment while searching linebreak.
377     * @return 0 means no linebreak was found, otherwise, return the distance between start token and linebreak
378     */
379 int searchReturnTokenDirectlyAfter(int pStart, boolean ignorecomment){
380    int ret = 0,j = 0;
381
382    if (items == null) return ret;
383
384    if ((pStart < 0 ) || (pStart+1 > size() - 1 ) ) return ret;
385    for (int i = pStart+1; i<size();i++)
386    {
387        j = i;
388        if (get(i).tokentype == ETokenType.ttwhitespace) continue;
389        if ( (
390                 (get(i).tokentype == ETokenType.ttsimplecomment)
391                ||(get(i).tokentype == ETokenType.ttbracketedcomment)
392              )  && ignorecomment  ) continue;
393
394        break;
395    }
396      if (get(j).tokentype == ETokenType.ttreturn) {ret = j - pStart;}
397
398    return ret;
399}
400
401public boolean returnbeforecurtoken(boolean ignorecomment){
402  return  returnbeforecurtoken(ignorecomment,true);
403}
404    /**
405     * Is there a linebreak before current token, comment is not ignored if ignorecomment is true,
406     * space is ignored.
407     * @return
408     */
409
410public boolean returnbeforecurtoken(boolean ignorecomment, boolean ignoreWhiteSpace){
411    boolean ret = false;
412    
413    if (items == null) return ret;
414
415    if (curpos <= 0) return ret;
416    if (curpos > size() - 1) return ret;
417    int i = curpos-1;
418
419    for (int j = i; j>=0;j--)
420    {
421        if ((ignoreWhiteSpace) && (get(j).tokentype == ETokenType.ttwhitespace)) continue;
422        if ((ignorecomment)&&((get(j).tokentype == ETokenType.ttsimplecomment)||(get(j).tokentype == ETokenType.ttbracketedcomment))) continue;
423        if (get(j).tokentype == ETokenType.ttreturn) ret = true;
424        break;
425    }
426
427    return ret;
428}
429
430    public TSourceToken searchToken(int targetTokenCode, String targetTokenText, TSourceToken startToken,  int range){
431            return searchToken(targetTokenCode,targetTokenText,startToken,range,0,false);
432    }
433    /**
434     *
435      * @param targetTokenCode, &gt; 0, search target token by token code;  = 0, search target token by token text
436     * @param targetTokenText
437     * @param startToken
438     * @param range, &gt; 0, search token after startToken
439     * = 0, just compare with this startToken,
440     * &lt; 0, search token before startToken
441     * @return
442     */
443public TSourceToken searchToken(int targetTokenCode, String targetTokenText, TSourceToken startToken,  int range, int stopTokenCode, boolean stopAtSemiColon){
444    TSourceToken ret = null;
445
446    if (items == null) {return ret;}
447
448    int ptokenpos = startToken.posinlist;
449
450    if ((ptokenpos < 0) || ( (ptokenpos > size() - 1)&&(range > 0)) ) {return ret;}
451
452    if ((range > 0) && (ptokenpos == size() - 1)) {return ret;}
453    if ((range < 0) && (ptokenpos == 0)) {return ret;}
454    if (range == 0){
455        if (targetTokenCode > 0){
456            if (startToken.tokencode == targetTokenCode ){
457                ret = startToken;
458            }
459        }else{
460            if (startToken.toString().equalsIgnoreCase(targetTokenText)){
461                ret = startToken;
462            }
463        }
464        return ret;
465    }
466
467    TSourceToken lctoken = null;
468
469    if (range > 0 ){
470        for (int i= ptokenpos + 1; i < size();i++)
471        {
472            lctoken = this.get(i);
473
474            if (isnonsolidtoken(lctoken,false)) { continue; }
475
476            if ( --range >= 0)
477            {
478                if (targetTokenCode > 0){
479                    if (lctoken.tokencode == targetTokenCode ){
480                        ret = lctoken;
481                        break;
482                    }
483                }else{
484                    if (lctoken.toString().equalsIgnoreCase(targetTokenText)){
485                        ret = lctoken;
486                        break;
487                    }
488                }
489            }else{
490                break;
491            }
492
493            if (stopTokenCode != 0){
494                if (lctoken.tokencode == stopTokenCode) break;
495            }
496
497            if ((lctoken.tokencode == ';')&& (stopAtSemiColon)) break;
498        }
499
500        range = 0;
501    }
502
503    if (range < 0 )
504    {
505        for (int i= ptokenpos - 1; i >= 0;i--)
506        {
507            lctoken = this.get(i);
508            if (isnonsolidtoken(lctoken,false)){continue;}
509            if (++range <= 0)
510            {
511                if (targetTokenCode > 0){
512                    if (lctoken.tokencode == targetTokenCode ){
513                        ret = lctoken;
514                        break;
515                    }
516                }else{
517                    if (lctoken.toString().equalsIgnoreCase(targetTokenText)){
518                        ret = lctoken;
519                        break;
520                    }
521                }
522            }else{
523                break;
524            }
525
526
527            if (stopTokenCode != 0){
528                if (lctoken.tokencode == stopTokenCode) break;
529            }
530            if ((lctoken.tokencode == ';')&& (stopAtSemiColon)) break;
531        }
532    }
533
534    return ret;
535}
536
537
538public void setTokenStatus(ETokenStatus ps,int pstart,int pend){
539   if (pstart < 0 ) return ;
540   if (pend > this.size() - 1 ) return;
541
542   for(int i=pstart;i<=pend;i++){
543       this.get(i).tokenstatus = ps;
544   }
545
546}
547
548public int indexOf(TSourceToken pst){
549    return items.indexOf(pst);
550}
551
552}