001
002package gudusoft.gsqlparser.pp.utils;
003
004import gudusoft.gsqlparser.ETokenStatus;
005import gudusoft.gsqlparser.ETokenType;
006import gudusoft.gsqlparser.TSourceToken;
007import gudusoft.gsqlparser.TSourceTokenList;
008import gudusoft.gsqlparser.pp.logger.PPLogger;
009import gudusoft.gsqlparser.pp.para.GFmtOpt;
010
011/**
012 * the helper class used for operating the source token
013 * 
014 * @author zhoujun
015 * 
016 */
017public class SourceTokenOperator
018{
019
020        public static int removeWhitespaceBackward( GFmtOpt opt,
021                        TSourceTokenList list, int end )
022        {
023                if ( end == 0 )
024                {
025                        return 0;
026                }
027
028                StringBuilder buf = new StringBuilder( );
029                buf.append( "removeWhitespaceAndReturnFromEnd:\ntargetToken:" )
030                                .append( list.get( end ).astext )
031                                .append( " newToken:" )
032                                .append( list.get( end ).astext.replaceAll( "\\n", "\\\\n" ) )
033                                .append( "(type:" )
034                                .append( list.get( end ).tokentype )
035                                .append( ")" );
036                int deleteWhitespaceCount = 0;
037                // int deleteReturn = 0;
038
039                int pos = end - 1;
040
041                // remove all white space before end item
042                TSourceToken token = list.get( pos );
043                while ( token.tokentype == ETokenType.ttwhitespace )
044                {
045
046                        if ( token.tokentype == ETokenType.ttwhitespace )
047                        {
048                                deleteWhitespaceCount++;
049                        }
050
051                        if ( opt.opearateSourceToken )
052                        {
053                                token.setReplaceToken( SourceTokenConstant.EMPTY );
054                        }
055
056                        pos--;
057                        if ( pos >= 0 )
058                        {
059                                token = token.container.get( pos );
060                        }
061                        else
062                        {
063                                break;
064                        }
065                }
066
067                if ( token.tokentype == ETokenType.ttreturn )
068                {
069                        StringBuilder b = new StringBuilder( );
070                        for ( int i = 0; i < token.astext.length( ); i++ )
071                        {
072                                char c = token.astext.charAt( i );
073                                if ( c != ' ' )
074                                {
075                                        b.append( c );
076                                }
077                        }
078                        token.astext = b.toString( );
079                }
080
081                buf.append( "\nDeleteWhiteSpace:" ).append( deleteWhitespaceCount );
082                PPLogger.info( 2, buf.toString( ), null );
083
084                return pos;
085        }
086
087        /**
088         * remove the white space and the return token from the end
089         * 
090         * @param list
091         * @param end
092         * @return the pos which is not white space and return token in the source
093         *         token list
094         */
095        public static int removeWhitespaceAndReturnFromEnd( GFmtOpt opt,
096                        TSourceTokenList list, int end )
097        {
098                if ( end == 0 )
099                {
100                        return 0;
101                }
102
103                StringBuilder buf = new StringBuilder( );
104                buf.append( "removeWhitespaceAndReturnFromEnd:\ntargetToken:" )
105                                .append( list.get( end ).astext )
106                                .append( " newToken:" )
107                                .append( list.get( end ).astext.replaceAll( "\\n", "\\\\n" ) )
108                                .append( "(type:" )
109                                .append( list.get( end ).tokentype )
110                                .append( ")" );
111                int deleteWhitespaceCount = 0;
112                int deleteReturn = 0;
113
114                int pos = end - 1;
115
116                // remove all white space before end item
117                TSourceToken token = list.get( pos );
118                while ( token.tokentype == ETokenType.ttwhitespace
119                                || token.tokentype == ETokenType.ttreturn )
120                {
121                        if ( token.tokentype == ETokenType.ttwhitespace )
122                        {
123                                deleteWhitespaceCount++;
124                        }
125
126                        if ( token.tokentype == ETokenType.ttreturn )
127                        {
128                                deleteReturn++;
129                        }
130
131                        if ( opt.opearateSourceToken )
132                        {
133                                token.setReplaceToken( SourceTokenConstant.EMPTY );
134                        }
135
136                        pos--;
137                        if ( pos >= 0 )
138                        {
139                                token = token.container.get( pos );
140                        }
141                        else
142                        {
143                                break;
144                        }
145                }
146
147                buf.append( "\nDeleteWhiteSpace:" )
148                                .append( deleteWhitespaceCount )
149                                .append( ", DeleteReturn:" )
150                                .append( deleteReturn );
151                PPLogger.info( 2, buf.toString( ), null );
152
153                return pos;
154        }
155
156        /**
157         * remove the white space and the return token from the end
158         * 
159         * @param token
160         * @return the pos which is not whitespace and return token in the source
161         *         token list
162         */
163        public static int removeWhitespaceAndReturnFromEnd( GFmtOpt opt,
164                        TSourceToken token )
165        {
166                if ( token == null )
167                {
168                        return -1;
169                }
170                return removeWhitespaceAndReturnFromEnd( opt,
171                                token.container,
172                                token.posinlist );
173        }
174
175        /**
176         * remove the white space and the return token before this token and after
177         * this token
178         * 
179         * @param opt
180         * @param token
181         */
182        public static void removeWhitespaceAndReturnFormBeforeAndAfter(
183                        GFmtOpt opt, TSourceToken token )
184        {
185                if ( token == null )
186                {
187                        return;
188                }
189                removeWhitespaceAndReturnFromEnd( opt, token );
190                removeWhitespaceAndReturnFromStart( opt,
191                                token.container,
192                                token.posinlist + 1 );
193
194        }
195
196        /**
197         * remove the white space and the return token
198         * 
199         * @param list
200         * @param start
201         * @param end
202         */
203        public static void removeWhitespaceAndReturn( GFmtOpt opt,
204                        TSourceTokenList list, int start, int end )
205        {
206                StringBuilder buf = new StringBuilder( );
207                buf.append( "removeWhitespaceAndReturn:\ntargetToken:" )
208                                .append( list.get( end ).astext )
209                                .append( " newToken:" )
210                                .append( list.get( end ).astext.replaceAll( "\\n", "\\\\n" ) )
211                                .append( "(type:" )
212                                .append( list.get( end ).tokentype )
213                                .append( ")" );
214                int deleteWhitespaceCount = 0;
215                int deleteReturn = 0;
216
217                for ( int i = start; i < end; i++ )
218                {
219                        if ( i < 0 || i > list.size( ) )
220                        {
221                                return;
222                        }
223                        TSourceToken token = list.get( i );
224                        if ( token.tokentype == ETokenType.ttwhitespace
225                                        || token.tokentype == ETokenType.ttreturn )
226                        {
227
228                                if ( token.tokentype == ETokenType.ttwhitespace )
229                                {
230                                        deleteWhitespaceCount++;
231                                }
232
233                                if ( token.tokentype == ETokenType.ttreturn )
234                                {
235                                        deleteReturn++;
236                                }
237                                if ( opt.opearateSourceToken )
238                                {
239                                        token.setReplaceToken( SourceTokenConstant.EMPTY );
240                                }
241                        }
242                }
243
244                buf.append( "\nDeleteWhiteSpace:" )
245                                .append( deleteWhitespaceCount )
246                                .append( ", DeleteReturn:" )
247                                .append( deleteReturn );
248                PPLogger.info( 2, buf.toString( ), null );
249
250        }
251
252        /**
253         * remove the white space and the return token from the end
254         * 
255         * @param list
256         */
257        public static int removeWhitespaceAndReturnFromStart( GFmtOpt opt,
258                        TSourceTokenList list, int startPos )
259        {
260                StringBuilder buf = new StringBuilder( );
261                if ( list.size( ) <= startPos )
262                {
263                        return list.size( ) - 1;
264                }
265                buf.append( "removeWhitespaceAndReturnFromStart:\ntargetToken:" )
266                                .append( list.get( startPos ).astext )
267                                .append( " newToken:" )
268                                .append( list.get( startPos ).astext.replaceAll( "\\n", "\\\\n" ) )
269                                .append( "(type:" )
270                                .append( list.get( startPos ).tokentype )
271                                .append( ")" );
272                int deleteWhitespaceCount = 0;
273                int deleteReturn = 0;
274
275                int pos = startPos;
276                // remove all white space before end item
277                TSourceToken token = list.get( pos );
278                while ( token.tokentype == ETokenType.ttwhitespace
279                                || token.tokentype == ETokenType.ttreturn )
280                {
281                        if ( token.tokentype == ETokenType.ttwhitespace )
282                        {
283                                deleteWhitespaceCount++;
284                        }
285
286                        if ( token.tokentype == ETokenType.ttreturn )
287                        {
288                                deleteReturn++;
289                        }
290
291                        if ( opt.opearateSourceToken )
292                        {
293                                token.setReplaceToken( SourceTokenConstant.EMPTY );
294                        }
295
296                        pos++;
297                        if ( pos < list.size( ) )
298                        {
299                                token = token.container.get( pos );
300                        }
301                        else
302                        {
303                                break;
304                        }
305                }
306
307                buf.append( "\nDeleteWhiteSpace:" )
308                                .append( deleteWhitespaceCount )
309                                .append( ", DeleteReturn:" )
310                                .append( deleteReturn );
311                PPLogger.info( 2, buf.toString( ), null );
312
313                return pos;
314        }
315
316        /**
317         * calculate the text length for all virtual token (which are call before
318         * tokens, after tokens and replace token)
319         * 
320         * @param list
321         * @param start
322         * @param end
323         * @return
324         */
325        public static int textLengthVT( TSourceTokenList list, int start, int end )
326        {
327                int total = 0;
328                for ( int i = start; i < end; i++ )
329                {
330                        TSourceToken token = list.get( i );
331
332                        if ( token.getTokensBefore( ).size( ) > 0 )
333                        {
334                                total += textLengthVT( token.getTokensBefore( ),
335                                                0,
336                                                token.getTokensBefore( ).size( ) );
337                        }
338                        if ( token.getReplaceToken( ) != null )
339                        {
340                                total += ( token.getReplaceToken( ).astext != null ? token.getReplaceToken( ).astext.length( )
341                                                : 0 );
342                        }
343                        else
344                        {
345                                total += ( token.astext != null ? token.astext.length( ) : 0 );
346                        }
347                        if ( token.getTokensAfter( ).size( ) > 0 )
348                        {
349                                total += textLengthVT( token.getTokensAfter( ),
350                                                0,
351                                                token.getTokensAfter( ).size( ) );
352                        }
353                }
354
355                return total;
356        }
357
358        /**
359         * calcaulate the text length from a given position to the line start. VT is
360         * the abbr for "virtual token" (which contains before tokens, after tokens
361         * and replace token)
362         * 
363         * @param list
364         * @param pos
365         * @return
366         */
367        public static int curColumnNumberVT( TSourceTokenList list, int pos )
368        {
369
370                int total = 0;
371
372                for ( int i = pos; i >= 0; i-- )
373                {
374                        TSourceToken token = list.get( i );
375                        
376                        if(token.tokenstatus == ETokenStatus.tsdeleted) {
377                                continue;
378                        } 
379
380                        // the after tokens in the last sourceToken should not calculated.
381                        if ( i != pos && token.getTokensAfter( ).size( ) > 0 )
382                        {
383                                for ( int j = token.getTokensAfter( ).size( ) - 1; j >= 0; j-- )
384                                {
385                                        TSourceToken after = token.getTokensAfter( ).get( j );
386                                        if ( after.tokentype != ETokenType.ttreturn )
387                                        {
388                                                total += ( after.astext != null ? after.astext.length( )
389                                                                : 0 );
390                                        }
391                                        else
392                                        {
393                                                return total;
394                                        }
395                                }
396                        }
397                        if ( i != pos )
398                        {
399                                if ( token.getReplaceToken( ) != null )
400                                {
401                                        if ( token.getReplaceToken( ).tokentype != ETokenType.ttreturn )
402                                        {
403                                                total += ( token.getReplaceToken( ).astext != null ? token.getReplaceToken( ).astext.length( )
404                                                                : 0 );
405                                        }
406                                        else
407                                        {
408                                                return total;
409                                        }
410                                }
411                                else
412                                {
413                                        if ( token.tokentype != ETokenType.ttreturn )
414                                        {
415                                                if(token.tokentype == ETokenType.ttsimplecomment) {
416                                                        if(token.nextToken()!=null &&
417                                                                        token.nextToken().astext!=null &&
418                                                                        token.nextToken().astext.trim().length() == 0) {
419                                                                total -= token.nextToken().astext.length( );
420                                                        }
421                                                        continue;
422                                                }
423                                                if(isOracleHint(token)) {
424                                                        if(token.nextToken()!=null &&
425                                                                        token.nextToken().astext!=null &&
426                                                                        token.nextToken().astext.trim().length() == 0) {
427                                                                total -= token.nextToken().astext.length( );
428                                                        }
429                                                        continue;
430                                                }
431                                                total += ( token.astext != null ? token.astext.length( )
432                                                                : 0 );
433                                        }
434                                        else
435                                        {
436                                                return total;
437                                        }
438                                }
439                        }
440
441                        if ( token.getTokensBefore( ).size( ) > 0 )
442                        {
443                                for ( int j = token.getTokensBefore( ).size( ) - 1; j >= 0; j-- )
444                                {
445                                        TSourceToken before = token.getTokensBefore( ).get( j );
446                                        if ( before.tokentype != ETokenType.ttreturn )
447                                        {
448                                                total += ( before.astext != null ? before.astext.length( )
449                                                                : 0 );
450                                        }
451                                        else
452                                        {
453                                                return total;
454                                        }
455                                }
456                        }
457                }
458
459                return total;
460        }
461
462        private static boolean isOracleHint(TSourceToken token) {
463                return token!=null && token.astext!=null && token.astext.startsWith("/*+");
464        }
465
466        /**
467         * calcaulate the text length from a given position to the line start. VT is
468         * the abbr for "virtual token" (which contains before tokens, after tokens
469         * and replace token)
470         * 
471         * @param token
472         * @return
473         */
474        public static int curColumnNumberVT( TSourceToken token )
475        {
476                return curColumnNumberVT( token.container, token.posinlist );
477        }
478
479        /**
480         * calculate the current indent length VT is the abbr for "virtual token"
481         * (which contains before tokens, after tokens and replace token)
482         * 
483         * @param list
484         * @param pos
485         * @return
486         */
487        public static int curIndentLenVT( TSourceTokenList list, int pos )
488        {
489                int indentLen = 0;
490                for ( int i = pos; i >= 0; i-- )
491                {
492                        TSourceToken token = list.get( i );
493                        
494                        if(token.tokenstatus == ETokenStatus.tsdeleted) {
495                                continue;
496                        } 
497
498                        // the after tokens in the last sourceToken should not calculated.
499                        if ( i != pos && token.getTokensAfter( ).size( ) > 0 )
500                        {
501                                for ( int j = token.getTokensAfter( ).size( ) - 1; j >= 0; j-- )
502                                {
503                                        TSourceToken after = token.getTokensAfter( ).get( j );
504                                        if ( after.tokentype == ETokenType.ttreturn )
505                                        {
506                                                return indentLen;
507                                        }
508                                        else if ( after.tokentype == ETokenType.ttwhitespace )
509                                        {
510                                                indentLen += ( after.astext != null ? after.astext.length( )
511                                                                : 0 );
512                                        }
513                                        else
514                                        {
515                                                indentLen = 0;
516                                        }
517                                }
518                        }
519
520                        if ( i != pos )
521                        {
522                                if ( token.getReplaceToken( ) != null )
523                                {
524                                        if ( token.getReplaceToken( ).tokentype == ETokenType.ttreturn )
525                                        {
526                                                return indentLen;
527                                        }
528                                        else if ( token.getReplaceToken( ).tokentype == ETokenType.ttwhitespace )
529                                        {
530                                                indentLen += ( token.getReplaceToken( ).astext != null ? token.getReplaceToken( ).astext.length( )
531                                                                : 0 );
532                                        }
533                                        else
534                                        {
535                                                indentLen = 0;
536                                        }
537
538                                }
539                                else
540                                {
541                                        if ( token.tokentype == ETokenType.ttreturn )
542                                        {
543                                                return indentLen;
544                                        }
545                                        else if ( token.tokentype == ETokenType.ttwhitespace )
546                                        {
547                                                indentLen += ( token.astext != null ? token.astext.length( )
548                                                                : 0 );
549                                        }
550                                        else
551                                        {
552                                                indentLen = 0;
553                                        }
554                                }
555                        }
556
557                        if ( token.getTokensBefore( ).size( ) > 0 )
558                        {
559                                for ( int j = token.getTokensBefore( ).size( ) - 1; j >= 0; j-- )
560                                {
561                                        TSourceToken before = token.getTokensBefore( ).get( j );
562                                        if ( before.tokentype == ETokenType.ttreturn )
563                                        {
564                                                return indentLen;
565                                        }
566                                        else if ( before.tokentype == ETokenType.ttwhitespace )
567                                        {
568                                                indentLen += ( before.astext != null ? before.astext.length( )
569                                                                : 0 );
570                                        }
571                                        else
572                                        {
573                                                indentLen = 0;
574                                        }
575                                }
576                        }
577
578                }
579                return indentLen;
580        }
581
582        /**
583         * calculate the current indent length VT is the abbr for "virtual token"
584         * (which contains before tokens, after tokens and replace token)
585         * 
586         * @param token
587         * @return
588         */
589        public static int curIndentLenVT( TSourceToken token )
590        {
591                return curIndentLenVT( token.container, token.posinlist );
592        }
593
594        /**
595         * create the white space source token
596         * 
597         * @param length
598         * @return
599         */
600        public static TSourceToken createWhitespaceSourceToken( int length )
601        {
602                return WhitespaceSourceTokenHelper.createWhitespaceSourceToken( length );
603        }
604
605        private static TSourceToken noFormatFlag = null;
606        static
607        {
608                noFormatFlag = new TSourceToken( "" );
609                noFormatFlag.tokentype = ETokenType.ttwhitespace;
610        }
611
612        public static TSourceToken createNoFormatFlagToken( )
613        {
614                return noFormatFlag;
615        }
616
617        public static TSourceToken createReturnSourceToken( )
618        {
619                TSourceToken t = new TSourceToken( "\n" );
620                t.tokentype = ETokenType.ttreturn;
621                return t;
622        }
623
624        /**
625         * combine all the white spaces into a single white space
626         * 
627         * @param list
628         * @param startPos
629         * @param endPos
630         */
631        public static void combineWhitespace( TSourceTokenList list, int startPos,
632                        int endPos )
633        {
634                boolean findWhitespace = false;
635                for ( int i = startPos; i < endPos; i++ )
636                {
637                        if ( i >= 0 && i < list.size( ) )
638                        {
639                                TSourceToken token = list.get( i );
640                                
641                                if(token.tokenstatus == ETokenStatus.tsdeleted) {
642                                        continue;
643                                } 
644                                
645                                if ( token.tokentype == ETokenType.ttwhitespace )
646                                {
647                                        token.setReplaceToken( SourceTokenConstant.EMPTY );
648                                        findWhitespace = true;
649                                }
650                        }
651                }
652                if ( findWhitespace )
653                {
654                        list.get( endPos )
655                                        .getTokensBefore( )
656                                        .add( createWhitespaceSourceToken( 1 ) );
657                }
658        }
659
660        /**
661         * insert the source token before the target source token
662         * 
663         * @param targetToken
664         * @param needAddToken
665         */
666        public static void addBefore( GFmtOpt opt, TSourceToken targetToken,
667                        TSourceToken needAddToken )
668        {
669                if ( needAddToken == null )
670                {
671                        return;
672                }
673
674                StringBuilder buf = new StringBuilder( );
675                buf.append( "AddBefore:\ntargetToken:" )
676                                .append( targetToken.astext )
677                                .append( "(pos:" )
678                                .append( targetToken.posinlist )
679                                .append( ")" )
680                                .append( " newToken:" )
681                                .append( needAddToken.astext.replaceAll( "\\n", "\\\\n" ) )
682                                .append( "(type:" )
683                                .append( needAddToken.tokentype )
684                                .append( ")" );
685
686                if ( targetToken.getTokensBefore( ).size( ) > 0 )
687                {
688                        buf.append( "\noldTokenBefore:" );
689                        for ( int i = 0; i < targetToken.getTokensBefore( ).size( ); i++ )
690                        {
691                                TSourceToken token = targetToken.getTokensBefore( ).get( i );
692                                
693                                if(token.tokenstatus == ETokenStatus.tsdeleted) {
694                                        continue;
695                                } 
696                                
697                                buf.append( "[" )
698                                                .append( token.astext != null ? token.astext.replaceAll( "\\n",
699                                                                "\\\\n" )
700                                                                : "" )
701                                                .append( "] " )
702                                                .append( "(type:" )
703                                                .append( token.tokentype )
704                                                .append( ")" );
705                        }
706                }
707
708                PPLogger.info( 2, buf.toString( ), null );
709
710                if ( opt.opearateSourceToken )
711                {
712                        targetToken.getTokensBefore( ).add( needAddToken );
713                }
714        }
715
716        public static void addAfter( GFmtOpt opt, TSourceToken targetToken,
717                        TSourceToken needAddToken )
718        {
719                if ( needAddToken == null )
720                {
721                        return;
722                }
723
724                StringBuilder buf = new StringBuilder( );
725                buf.append( "AddAfter:\ntargetToken:" )
726                                .append( targetToken.astext )
727                                .append( "(pos:" )
728                                .append( targetToken.posinlist )
729                                .append( ")" )
730                                .append( " newToken:" )
731                                .append( needAddToken.astext != null ? needAddToken.astext.replaceAll( "\\n",
732                                                "\\\\n" )
733                                                : "" )
734                                .append( "(type:" )
735                                .append( needAddToken.tokentype )
736                                .append( ")" );
737
738                if ( targetToken.getTokensAfter( ).size( ) > 0 )
739                {
740                        buf.append( "\noldTokenAfter:" );
741                        for ( int i = 0; i < targetToken.getTokensAfter( ).size( ); i++ )
742                        {
743                                TSourceToken token = targetToken.getTokensAfter( ).get( i );
744                                
745                                if(token.tokenstatus == ETokenStatus.tsdeleted) {
746                                        continue;
747                                } 
748                                
749                                buf.append( "[" )
750                                                .append( token.astext != null ? token.astext.replaceAll( "\\n",
751                                                                "\\\\n" )
752                                                                : "" )
753                                                .append( "] " )
754                                                .append( "(type:" )
755                                                .append( token.tokentype )
756                                                .append( ")" );
757                        }
758                }
759
760                PPLogger.info( 2, buf.toString( ), null );
761
762                if ( opt.opearateSourceToken )
763                {
764                        targetToken.getTokensAfter( ).add( needAddToken );
765                }
766        }
767
768        /**
769         * remove all source token in the before source token list VT is the abbr
770         * for "virtual token" (that this method will operates before tokens, after
771         * tokens and replace token)
772         * 
773         * @param targetToken
774         */
775        public static void removeAllBeforeTokenVT( GFmtOpt opt,
776                        TSourceToken targetToken )
777        {
778                StringBuilder buf = new StringBuilder( );
779                buf.append( "RemoveAllBeforeTokenVT:" );
780                while ( targetToken.getTokensBefore( ).size( ) > 0 )
781                {
782                        TSourceToken token = targetToken.getTokensBefore( ).get( 0 );
783                        
784                        if(token.tokenstatus == ETokenStatus.tsdeleted) {
785                                continue;
786                        } 
787                        
788                        buf.append( "\nremoveToken:" )
789                                        .append( "[" )
790                                        .append( token.astext != null ? token.astext.replaceAll( "\\n",
791                                                        "\\\\n" )
792                                                        : "" )
793                                        .append( "] " )
794                                        .append( "(type:" )
795                                        .append( token.tokentype )
796                                        .append( ")" );
797                        if ( opt.opearateSourceToken )
798                        {
799                                targetToken.getTokensBefore( ).remove( 0 );
800                        }
801                }
802                PPLogger.info( 2, buf.toString( ), null );
803
804        }
805
806        public static void removeThisToken( TSourceToken token )
807        {
808                token.setReplaceToken( SourceTokenOperator.createWhitespaceSourceToken( 1 ) );
809        }
810}