KDevelop API Documentation

ASFormatter.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1998,1999,2000,2001,2002 Tal Davidson. All rights reserved.
00003  *
00004  * ASFormatter.cpp
00005  * by Tal Davidson (davidsont@bigfoot.com)
00006  * This file is a part of "Artistic Style" - an indentater and reformatter
00007  * of C, C++, C# and Java source files.
00008  *
00009  * The "Artistic Style" project, including all files needed to compile it,
00010  * is free software; you can redistribute it and/or use it and/or modify it
00011  * under the terms of the GNU General Public License as published 
00012  * by the Free Software Foundation; either version 2 of the License, 
00013  * or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018  *
00019  * You should have received a copy of the GNU General Public
00020  * License along with this program.
00021  *
00022  *
00023  * Patches:
00024  * 26 November 1998 - Richard Bullington -
00025  *        A correction of line-breaking in headers following '}',
00026  *        was created using a variation of a  patch by Richard Bullington.
00027  */
00028 
00029 #include "compiler_defines.h"
00030 #include "astyle.h"
00031 
00032 #include <string>
00033 #include <cctype>
00034 #include <vector>
00035 #include <algorithm>
00036 #include <iostream>
00037 
00038 
00039 #define INIT_CONTAINER(container, value)     {if ( (container) != NULL ) delete (container); (container) = (value); }
00040 #define DELETE_CONTAINER(container)          {if ( (container) != NULL ) delete (container) ; }
00041 #define IS_A(a,b)                            ( ((a) & (b)) == (b))
00042 #ifdef USES_NAMESPACE
00043 using namespace std;
00044 
00045 namespace astyle {
00046 #endif
00047 
00048 
00049 bool ASFormatter::calledInitStatic = false;
00050 vector<const string*> ASFormatter::headers;
00051 vector<const string*> ASFormatter::nonParenHeaders;
00052 vector<const string*> ASFormatter::preprocessorHeaders;
00053 vector<const string*> ASFormatter::preDefinitionHeaders;
00054 vector<const string*> ASFormatter::preCommandHeaders;
00055 vector<const string*> ASFormatter::operators;
00056 vector<const string*> ASFormatter::assignmentOperators;
00057 
00061 ASFormatter::ASFormatter() {
00062     staticInit();
00063 
00064     preBracketHeaderStack = NULL;
00065     bracketTypeStack = NULL;
00066     parenStack = NULL;
00067 
00068     sourceIterator = NULL;
00069     bracketFormatMode = NONE_MODE;
00070     shouldPadOperators = false;
00071     shouldPadParenthesies = false;
00072     shouldBreakOneLineBlocks = true;
00073     shouldBreakOneLineStatements = true;
00074     shouldConvertTabs = false;
00075     shouldBreakBlocks = false;
00076     shouldBreakClosingHeaderBlocks = false;
00077     shouldBreakClosingHeaderBrackets = false;
00078     shouldBreakElseIfs = false;
00079 }
00080 
00084 ASFormatter::~ASFormatter() {
00085     DELETE_CONTAINER( preBracketHeaderStack );
00086 }
00087 
00091 void ASFormatter::staticInit() {
00092     if (calledInitStatic)
00093         return;
00094 
00095     calledInitStatic = true;
00096 
00097     headers.push_back(&AS_IF);
00098     headers.push_back(&AS_ELSE);
00099     headers.push_back(&AS_DO);
00100     headers.push_back(&AS_WHILE);
00101     headers.push_back(&AS_FOR);
00102     headers.push_back(&AS_SYNCHRONIZED);
00103     headers.push_back(&AS_TRY);
00104     headers.push_back(&AS_CATCH);
00105     headers.push_back(&AS_FINALLY);
00106     headers.push_back(&AS_SWITCH);
00107     headers.push_back(&AS_TEMPLATE);
00108     headers.push_back(&AS_FOREACH);
00109     headers.push_back(&AS_LOCK);
00110     headers.push_back(&AS_UNSAFE);
00111     headers.push_back(&AS_FIXED);
00112     headers.push_back(&AS_GET);
00113     headers.push_back(&AS_SET);
00114     headers.push_back(&AS_ADD);
00115     headers.push_back(&AS_REMOVE);
00116 
00117     nonParenHeaders.push_back(&AS_ELSE);
00118     nonParenHeaders.push_back(&AS_DO);
00119     nonParenHeaders.push_back(&AS_TRY);
00120     nonParenHeaders.push_back(&AS_FINALLY);
00121     nonParenHeaders.push_back(&AS_UNSAFE);
00122     nonParenHeaders.push_back(&AS_GET);
00123     nonParenHeaders.push_back(&AS_SET);
00124     nonParenHeaders.push_back(&AS_ADD);
00125     nonParenHeaders.push_back(&AS_REMOVE);
00126 
00127     //    nonParenHeaders.push_back(&AS_TEMPLATE);
00128 
00129     preDefinitionHeaders.push_back(&AS_CLASS);
00130     preDefinitionHeaders.push_back(&AS_INTERFACE);
00131     preDefinitionHeaders.push_back(&AS_NAMESPACE);
00132     preDefinitionHeaders.push_back(&AS_STRUCT);
00133 
00134     preCommandHeaders.push_back(&AS_EXTERN);
00135     preCommandHeaders.push_back(&AS_THROWS);
00136     preCommandHeaders.push_back(&AS_CONST);
00137 
00138     preprocessorHeaders.push_back(&AS_BAR_DEFINE);
00144 
00145     operators.push_back(&AS_PLUS_ASSIGN);
00146     operators.push_back(&AS_MINUS_ASSIGN);
00147     operators.push_back(&AS_MULT_ASSIGN);
00148     operators.push_back(&AS_DIV_ASSIGN);
00149     operators.push_back(&AS_MOD_ASSIGN);
00150     operators.push_back(&AS_OR_ASSIGN);
00151     operators.push_back(&AS_AND_ASSIGN);
00152     operators.push_back(&AS_XOR_ASSIGN);
00153     operators.push_back(&AS_EQUAL);
00154     operators.push_back(&AS_PLUS_PLUS);
00155     operators.push_back(&AS_MINUS_MINUS);
00156     operators.push_back(&AS_NOT_EQUAL);
00157     operators.push_back(&AS_GR_EQUAL);
00158     operators.push_back(&AS_GR_GR_GR_ASSIGN);
00159     operators.push_back(&AS_GR_GR_ASSIGN);
00160     operators.push_back(&AS_GR_GR_GR);
00161     operators.push_back(&AS_GR_GR);
00162     operators.push_back(&AS_LS_EQUAL);
00163     operators.push_back(&AS_LS_LS_LS_ASSIGN);
00164     operators.push_back(&AS_LS_LS_ASSIGN);
00165     operators.push_back(&AS_LS_LS_LS);
00166     operators.push_back(&AS_LS_LS);
00167     operators.push_back(&AS_ARROW);
00168     operators.push_back(&AS_AND);
00169     operators.push_back(&AS_OR);
00170     operators.push_back(&AS_COLON_COLON);
00171 
00175 
00176     operators.push_back(&AS_PLUS);
00177     operators.push_back(&AS_MINUS);
00178     operators.push_back(&AS_MULT);
00179     operators.push_back(&AS_DIV);
00180     operators.push_back(&AS_MOD);
00181     operators.push_back(&AS_QUESTION);
00182     operators.push_back(&AS_COLON);
00183     operators.push_back(&AS_ASSIGN);
00184     operators.push_back(&AS_LS);
00185     operators.push_back(&AS_GR);
00186     operators.push_back(&AS_NOT);
00187     operators.push_back(&AS_BIT_OR);
00188     operators.push_back(&AS_BIT_AND);
00189     operators.push_back(&AS_BIT_NOT);
00190     operators.push_back(&AS_BIT_XOR);
00191     operators.push_back(&AS_OPERATOR);
00192     operators.push_back(&AS_COMMA);
00193     //    operators.push_back(&AS_SEMICOLON);
00194     operators.push_back(&AS_RETURN);
00195 
00196     assignmentOperators.push_back(&AS_PLUS_ASSIGN);
00197     assignmentOperators.push_back(&AS_MINUS_ASSIGN);
00198     assignmentOperators.push_back(&AS_MULT_ASSIGN);
00199     assignmentOperators.push_back(&AS_DIV_ASSIGN);
00200     assignmentOperators.push_back(&AS_MOD_ASSIGN);
00201     assignmentOperators.push_back(&AS_XOR_ASSIGN);
00202     assignmentOperators.push_back(&AS_OR_ASSIGN);
00203     assignmentOperators.push_back(&AS_AND_ASSIGN);
00204     assignmentOperators.push_back(&AS_GR_GR_GR_ASSIGN);
00205     assignmentOperators.push_back(&AS_LS_LS_LS_ASSIGN);
00206     assignmentOperators.push_back(&AS_ASSIGN);
00207 }
00208 
00221 void ASFormatter::init(ASSourceIterator *si) {
00222     ASBeautifier::init(si);
00223     sourceIterator = si;
00224 
00225     INIT_CONTAINER( preBracketHeaderStack, new vector<const string*> );
00226     INIT_CONTAINER( bracketTypeStack, new vector<BracketType> );
00227     bracketTypeStack->push_back(DEFINITION_TYPE);
00228     INIT_CONTAINER( parenStack, new vector<int> );
00229     parenStack->push_back(0);
00230 
00231     currentHeader = NULL;
00232     currentLine = string("");
00233     formattedLine = "";
00234     currentChar = ' ';
00235     previousCommandChar = ' ';
00236     previousNonWSChar = ' ';
00237     quoteChar = '"';
00238     charNum = 0;
00239     previousOperator = NULL;
00240 
00241     isVirgin = true;
00242     isInLineComment = false;
00243     isInComment = false;
00244     isInPreprocessor = false;
00245     doesLineStartComment = false;
00246     isInQuote = false;
00247     isSpecialChar = false;
00248     isNonParenHeader = true;
00249     foundPreDefinitionHeader = false;
00250     foundPreCommandHeader = false;
00251     foundQuestionMark = false;
00252     isInLineBreak = false;
00253     endOfCodeReached = false;
00254     isLineReady = false;
00255     isPreviousBracketBlockRelated = true;
00256     isInPotentialCalculation = false;
00257     //foundOneLineBlock = false;
00258     shouldReparseCurrentChar = false;
00259     passedSemicolon = false;
00260     passedColon = false;
00261     isInTemplate = false;
00262     shouldBreakLineAfterComments = false;
00263     isImmediatelyPostComment = false;
00264     isImmediatelyPostLineComment = false;
00265     isImmediatelyPostEmptyBlock = false;
00266 
00267     isPrependPostBlockEmptyLineRequested = false;
00268     isAppendPostBlockEmptyLineRequested = false;
00269     prependEmptyLine = false;
00270 
00271     foundClosingHeader = false;
00272     previousReadyFormattedLineLength = 0;
00273 
00274     isImmediatelyPostHeader = false;
00275     isInHeader = false;
00276 }
00277 
00284 string ASFormatter::nextLine() {
00285     const string *newHeader;
00286     bool isCharImmediatelyPostComment = false;
00287     bool isPreviousCharPostComment = false;
00288     bool isCharImmediatelyPostLineComment = false;
00289     bool isInVirginLine = isVirgin;
00290     bool isCharImmediatelyPostOpenBlock = false;
00291     bool isCharImmediatelyPostCloseBlock = false;
00292     bool isCharImmediatelyPostTemplate = false;
00293     bool isCharImmediatelyPostHeader = false;
00294 
00295     if (!isFormattingEnabled())
00296         return ASBeautifier::nextLine();
00297 
00298     while (!isLineReady) {
00299         if (shouldReparseCurrentChar)
00300             shouldReparseCurrentChar = false;
00301         else if (!getNextChar()) {
00302             breakLine();
00303             return beautify(readyFormattedLine);
00304         } else // stuff to do when reading a new character...
00305         {
00306             // make sure that a virgin '{' at the begining ofthe file will be treated as a block...
00307             if (isInVirginLine && currentChar == '{')
00308                 previousCommandChar = '{';
00309             isPreviousCharPostComment = isCharImmediatelyPostComment;
00310             isCharImmediatelyPostComment = false;
00311             isCharImmediatelyPostTemplate = false;
00312             isCharImmediatelyPostHeader = false;
00313         }
00314 
00315         if (isInLineComment) {
00316             appendCurrentChar();
00317 
00318             // explicitely break a line when a line comment's end is found.
00319             if (/*bracketFormatMode == ATTACH_MODE &&*/ charNum+1 == (int)currentLine.length()) {
00320                 isInLineBreak = true;
00321                 isInLineComment = false;
00322                 isImmediatelyPostLineComment = true;
00323                 currentChar = 0;  //make sure it is a neutral char.
00324             }
00325 
00326 
00327 
00328             continue;
00329         } else if (isInComment) {
00330             if (isSequenceReached(AS_CLOSE_COMMENT)) {
00331                 isInComment = false;
00332                 isImmediatelyPostComment = true;
00333                 appendSequence(AS_CLOSE_COMMENT);
00334                 goForward(1);
00335             } else
00336                 appendCurrentChar();
00337 
00338             continue;
00339         }
00340 
00341         // not in line comment or comment
00342 
00343         else if (isInQuote) {
00344             if (isSpecialChar) {
00345                 isSpecialChar = false;
00346                 appendCurrentChar();
00347             } else if (currentChar == '\\') {
00348                 isSpecialChar = true;
00349                 appendCurrentChar();
00350             } else if (quoteChar == currentChar) {
00351                 isInQuote = false;
00352                 appendCurrentChar();
00353             } else {
00354                 appendCurrentChar();
00355             }
00356 
00357             continue;
00358         }
00359 
00360 
00361 
00362         // handle white space - needed to simplify the rest.
00363         if (isWhiteSpace(currentChar) || isInPreprocessor) {
00365             appendCurrentChar();
00366             continue;
00367         }
00368 
00369         /* not in MIDDLE of quote or comment or white-space of any type ... */
00370 
00371         if (isSequenceReached(AS_OPEN_LINE_COMMENT)) {
00372             isInLineComment = true;
00373             if (shouldPadOperators)
00374                 appendSpacePad();
00375             appendSequence(AS_OPEN_LINE_COMMENT);
00376             goForward(1);
00377             continue;
00378         } else if (isSequenceReached(AS_OPEN_COMMENT)) {
00379             isInComment = true;
00380             if (shouldPadOperators)
00381                 appendSpacePad();
00382             appendSequence(AS_OPEN_COMMENT);
00383             goForward(1);
00384             continue;
00385         } else if (currentChar == '"' || currentChar == '\'') {
00386             isInQuote = true;
00387             quoteChar = currentChar;
00390             appendCurrentChar();
00391             continue;
00392         }
00393 
00394         /* not in quote or comment or white-space of any type ... */
00395 
00396         // check if in preprocessor
00397         // ** isInPreprocessor will be automatically reset at the begining
00398         //    of a new line in getnextChar()
00399         if (currentChar == '#')
00400             isInPreprocessor = true;
00401 
00402         if (isInPreprocessor) {
00403             appendCurrentChar();
00404             continue;
00405         }
00406 
00407         /* not in preprocessor ... */
00408 
00409         if (isImmediatelyPostComment) {
00410             isImmediatelyPostComment = false;
00411             isCharImmediatelyPostComment = true;
00412         }
00413 
00414         if (isImmediatelyPostLineComment) {
00415             isImmediatelyPostLineComment = false;
00416             isCharImmediatelyPostLineComment = true;
00417         }
00418 
00419         if (shouldBreakLineAfterComments) {
00420             shouldBreakLineAfterComments = false;
00421             shouldReparseCurrentChar = true;
00422             breakLine();
00423             continue;
00424         }
00425 
00426         // reset isImmediatelyPostHeader information
00427         if (isImmediatelyPostHeader) {
00428             isImmediatelyPostHeader = false;
00429             isCharImmediatelyPostHeader = true;
00430 
00431             // Make sure headers are broken from their succeeding blocks
00432             // (e.g.
00433             //     if (isFoo) DoBar();
00434             //  should become
00435             //     if (isFoo)
00436             //         DoBar;
00437             // )
00438             // But treat else if() as a special case which should not be broken!
00439             if (shouldBreakOneLineStatements) {
00440                 // if may break 'else if()'s, ythen simply break the line
00441 
00442                 if (shouldBreakElseIfs)
00443                     isInLineBreak = true;
00444 
00445                 else {
00446                     // make sure 'else if()'s are not broken.
00447 
00448                     bool isInElseIf = false;
00449                     const string *upcomingHeader;
00450 
00451                     upcomingHeader = findHeader(headers);
00452                     if (currentHeader == &AS_ELSE && upcomingHeader == &AS_IF)
00453                         isInElseIf = true;
00454 
00455                     if (!isInElseIf)
00456                         isInLineBreak = true;  
00457                 }
00458 
00459 
00460 
00461             }
00462         }
00463 
00464         if (passedSemicolon) {
00465             passedSemicolon = false;
00466             if (parenStack->back() == 0) {
00467                 shouldReparseCurrentChar = true;
00468                 isInLineBreak = true;
00469                 continue;
00470             }
00471         }
00472 
00473         if (passedColon) {
00474             passedColon = false;
00475             if (parenStack->back() == 0) {
00476                 shouldReparseCurrentChar = true;
00477                 isInLineBreak = true;
00478                 continue;
00479             }
00480         }
00481 
00482         // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
00483         // If so, set isInTemplate to true
00484         //
00485         if (!isInTemplate && currentChar == '<') {
00486             int templateDepth = 0;
00487             const string *oper;
00488             for ( int i=charNum;
00489                     i< (int)currentLine.length();
00490                     i += (oper ? oper->length() : 1) ) {
00491                 oper = ASBeautifier::findHeader(currentLine, i, operators);
00492 
00493                 if (oper == &AS_LS) {
00494                     templateDepth++;
00495                 } else if (oper == &AS_GR) {
00496                     templateDepth--;
00497                     if (templateDepth == 0) {
00498                         // this is a template!
00499                         //
00500                         isInTemplate = true;
00501                         break;
00502                     }
00503                 } else if (oper == &AS_COMMA               // comma,     e.g. A<int, char>
00504                            || oper == &AS_BIT_AND       // reference, e.g. A<int&>
00505                            || oper == &AS_MULT          // pointer,   e.g. A<int*>
00506                            || oper == &AS_COLON_COLON)  // ::,        e.g. std::string
00507                 {
00508                     continue;
00509                 } else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i])) {
00510                     // this is not a template -> leave...
00511                     //
00512                     isInTemplate = false;
00513                     break;
00514                 }
00515             }
00516         }
00517 
00518         // handle parenthesies
00519         //
00520         if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<')) {
00521             parenStack->back()++;
00522         } else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>')) {
00523             parenStack->back()--;
00524             if (isInTemplate && parenStack->back() == 0) {
00525                 isInTemplate = false;
00526                 isCharImmediatelyPostTemplate = true;
00527             }
00528 
00529             // check if this parenthesis closes a header, e.g. if (...), while (...)
00530             //
00531             if (isInHeader && parenStack->back() == 0) {
00532                 isInHeader = false;
00533                 isImmediatelyPostHeader = true;
00534             }
00535 
00536         }
00537 
00538         // handle brackets
00539         //
00540         BracketType bracketType = NULL_TYPE;
00541 
00542         if (currentChar == '{') {
00543             bracketType = getBracketType();
00544             foundPreDefinitionHeader = false;
00545             foundPreCommandHeader = false;
00546 
00547             bracketTypeStack->push_back(bracketType);
00548             preBracketHeaderStack->push_back(currentHeader);
00549             currentHeader = NULL;
00550 
00551             isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
00552         } else if (currentChar == '}') {
00553             // if a request has been made to append a post block empty line,
00554             // but the block exists immediately before a closing bracket,
00555             // then there is not need for the post block empty line.
00556             //
00557             isAppendPostBlockEmptyLineRequested = false;
00558 
00559             if (!bracketTypeStack->empty()) {
00560                 bracketType = bracketTypeStack->back();
00561                 bracketTypeStack->pop_back();
00562 
00563                 isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
00564             }
00565 
00566             if (!preBracketHeaderStack->empty()) {
00567                 currentHeader = preBracketHeaderStack->back();
00568                 preBracketHeaderStack->pop_back();
00569             } else
00570                 currentHeader = NULL;
00571         }
00572 
00573         if (!IS_A(bracketType, ARRAY_TYPE)) {
00574 
00575             if (currentChar == '{') {
00576                 parenStack->push_back(0);
00577             } else if (currentChar == '}') {
00578                 if (!parenStack->empty()) {
00579                     parenStack->pop_back();
00580                 }
00581             }
00582 
00583             if (bracketFormatMode != NONE_MODE) {
00584                 if (currentChar == '{') {
00585                     if ( ( bracketFormatMode == ATTACH_MODE
00586                             || bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2
00587                             && IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], COMMAND_TYPE) /*&& isInLineBreak*/)
00588                             && !isCharImmediatelyPostLineComment ) {
00589                         appendSpacePad();
00590                         if (!isCharImmediatelyPostComment // do not attach '{' to lines that end with /**/ comments.
00591                                 && previousCommandChar != '{'
00592                                 && previousCommandChar != '}'
00593                                 && previousCommandChar != ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
00594                             appendCurrentChar(false);
00595                         else
00596                             appendCurrentChar(true);
00597                         continue;
00598                     } else if (bracketFormatMode == BREAK_MODE
00599                                || bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2
00600                                && IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], DEFINITION_TYPE)) {
00601                         if ( shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE) )
00602                             breakLine();
00603                         appendCurrentChar();
00604                         continue;
00605                     }
00606                 } else if (currentChar == '}') {
00607                     // bool origLineBreak = isInLineBreak;
00608 
00609                     // mark state of immediately after empty block
00610                     // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
00611                     if (previousCommandChar == '{')
00612                         isImmediatelyPostEmptyBlock = true;
00613 
00614                     if ( (!(previousCommandChar == '{' && isPreviousBracketBlockRelated) )          // this '{' does not close an empty block
00615                             && (shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))  // astyle is allowed to break on line blocks
00616                             && !isImmediatelyPostEmptyBlock)                                        // this '}' does not immediately follow an empty block
00617                     {
00618                         breakLine();
00619                         appendCurrentChar();
00620                     } else {
00621                         if (!isCharImmediatelyPostComment)
00622                             isInLineBreak = false;
00623                         appendCurrentChar();
00624                         if (shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))
00625                             shouldBreakLineAfterComments = true;
00626                     }
00627 
00628                     if (shouldBreakBlocks) {
00629                         isAppendPostBlockEmptyLineRequested =true;
00630                     }
00631 
00632                     continue;
00633                 }
00634             }
00635         }
00636 
00637         if ( ( (previousCommandChar == '{'
00638                 && isPreviousBracketBlockRelated)
00639 
00640                 || (previousCommandChar == '}'
00641                     && !isImmediatelyPostEmptyBlock   // <--
00642                     && isPreviousBracketBlockRelated
00643                     && !isPreviousCharPostComment    // <-- Fixes wrongly appended newlines after '}' immediately after comments... 10/9/1999
00644                     && peekNextChar() != ' '))
00645 
00646                 &&  (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE)) ) {
00647             isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
00648             isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
00649 
00650             previousCommandChar = ' ';
00651             isInLineBreak = true;  //<----
00652         }
00653 
00654         // reset block handling flags
00655 
00656 
00657 
00658         isImmediatelyPostEmptyBlock = false;
00659 
00660         // look for headers
00661         if (!isInTemplate) {
00662             if ( (newHeader = findHeader(headers)) != NULL) {
00663                 foundClosingHeader = false;
00664                 const string *previousHeader;
00665 
00666                 // recognize closing headers of do..while, if..else, try..catch..finally
00667                 if ( (newHeader == &AS_ELSE && currentHeader == &AS_IF)
00668                         || (newHeader == &AS_WHILE && currentHeader == &AS_DO)
00669                         || (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
00670                         || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
00671                         || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
00672                         || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH) )
00673                     foundClosingHeader = true;
00674 
00675                 previousHeader = currentHeader;
00676                 currentHeader = newHeader;
00677 
00678                 // If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch')
00679                 // to their preceding bracket,
00680                 // But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set!
00681                 if (!shouldBreakClosingHeaderBrackets && foundClosingHeader && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE) && previousNonWSChar == '}') {
00682                     isInLineBreak = false;
00683                     appendSpacePad();
00684 
00685                     if (shouldBreakBlocks)
00686                         isAppendPostBlockEmptyLineRequested = false;
00687                 }
00688 
00689                 //Check if a template definition as been reached, e.g. template<class A>
00690                 if (newHeader == &AS_TEMPLATE) {
00691                     isInTemplate = true;
00692                 }
00693 
00694                 // check if the found header is non-paren header
00695                 isNonParenHeader = ( find(nonParenHeaders.begin(), nonParenHeaders.end(),
00696                                           newHeader) != nonParenHeaders.end() );
00697                 appendSequence(*currentHeader);
00698                 goForward(currentHeader->length() - 1);
00699                 // if padding is on, and a paren-header is found
00700                 // then add a space pad after it.
00701                 if (shouldPadOperators && !isNonParenHeader)
00702                     appendSpacePad();
00703 
00704 
00705                 // Signal that a header has been reached
00706                 // *** But treat a closing while() (as in do...while)
00707                 //     as if it where NOT a header since a closing while()
00708                 //     should never have a block after it!
00709                 if (!(foundClosingHeader && currentHeader == &AS_WHILE)) {
00710                     isInHeader = true;
00711                     if (isNonParenHeader) {
00712                         isImmediatelyPostHeader = true;
00713                         isInHeader = false;
00714                     }
00715                 }
00716 
00717                 if (currentHeader == &AS_IF && previousHeader == &AS_ELSE)
00718                     isInLineBreak = false;
00719 
00720                 if (shouldBreakBlocks) {
00721                     if (previousHeader == NULL
00722                             && !foundClosingHeader
00723                             && !isCharImmediatelyPostOpenBlock) {
00724                         isPrependPostBlockEmptyLineRequested = true;
00725                     }
00726 
00727                     if (currentHeader == &AS_ELSE
00728                             || currentHeader == &AS_CATCH
00729                             || currentHeader == &AS_FINALLY
00730                             || foundClosingHeader) {
00731                         isPrependPostBlockEmptyLineRequested = false;
00732                     }
00733 
00734                     if (shouldBreakClosingHeaderBlocks
00735                             &&  isCharImmediatelyPostCloseBlock) {
00736                         isPrependPostBlockEmptyLineRequested = true;
00737                     }
00738 
00739                 }
00740 
00741                 continue;
00742             } else if ( (newHeader = findHeader(preDefinitionHeaders)) != NULL) {
00743                 foundPreDefinitionHeader = true;
00744                 appendSequence(*newHeader);
00745                 goForward(newHeader->length() - 1);
00746 
00747                 if (shouldBreakBlocks)
00748                     isPrependPostBlockEmptyLineRequested = true;
00749 
00750                 continue;
00751             } else if ( (newHeader = findHeader(preCommandHeaders)) != NULL) {
00752                 foundPreCommandHeader = true;
00753                 appendSequence(*newHeader);
00754                 goForward(newHeader->length() - 1);
00755 
00756                 continue;
00757             }
00758         }
00759 
00760         if (previousNonWSChar == '}' || currentChar == ';') {
00761             if (shouldBreakOneLineStatements && currentChar == ';'
00762                     && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE))) {
00763                 passedSemicolon = true;
00764             }
00765 
00766             if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0) {
00767                 isAppendPostBlockEmptyLineRequested = true;
00768             }
00769 
00770             if (currentChar != ';')
00771                 currentHeader = NULL; //DEVEL: is this ok?
00772 
00773             foundQuestionMark = false;
00774             foundPreDefinitionHeader = false;
00775             foundPreCommandHeader = false;
00776             isInPotentialCalculation = false;
00777 
00778         }
00779 
00780         if (currentChar == ':'
00781                 && shouldBreakOneLineStatements
00782                 && !foundQuestionMark // not in a ... ? ... : ... sequence
00783                 && !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar
00784                 && previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
00785                 && previousChar != ':' // not part of '::'
00786                 && peekNextChar() != ':') // not part of '::'
00787         {
00788             passedColon = true;
00789             if (shouldBreakBlocks)
00790                 isPrependPostBlockEmptyLineRequested = true;
00791         }
00792 
00793         if (currentChar == '?')
00794             foundQuestionMark = true;
00795 
00796         if (shouldPadOperators) {
00797             if ((newHeader = findHeader(operators)) != NULL) {
00798                 bool shouldPad = (newHeader != &AS_COLON_COLON
00799                                   && newHeader != &AS_PAREN_PAREN
00800                                   && newHeader != &AS_BLPAREN_BLPAREN
00801                                   && newHeader != &AS_PLUS_PLUS
00802                                   && newHeader != &AS_MINUS_MINUS
00803                                   && newHeader != &AS_NOT
00804                                   && newHeader != &AS_BIT_NOT
00805                                   && newHeader != &AS_ARROW
00806                                   && newHeader != &AS_OPERATOR
00807                                   && !(newHeader == &AS_MINUS && isInExponent())
00808                                   && !(newHeader == &AS_PLUS && isInExponent())
00809                                   && previousOperator != &AS_OPERATOR
00810                                   && !((newHeader == &AS_MULT || newHeader == &AS_BIT_AND)
00811                                        && isPointerOrReference())
00812                                   && !( (isInTemplate || isCharImmediatelyPostTemplate)
00813                                         && (newHeader == &AS_LS || newHeader == &AS_GR))
00814                                  );
00815 
00816                 if (!isInPotentialCalculation)
00817                     if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader)
00818                             != assignmentOperators.end())
00819                         isInPotentialCalculation = true;
00820 
00821                 // pad before operator
00822                 if (shouldPad
00823                         && !(newHeader == &AS_COLON && !foundQuestionMark)
00824                         && newHeader != &AS_SEMICOLON
00825                         && newHeader != &AS_COMMA)
00826                     appendSpacePad();
00827                 appendSequence(*newHeader);
00828                 goForward(newHeader->length() - 1);
00829 
00830                 // since this block handles '()' and '[]',
00831                 // the parenStack must be updated here accordingly!
00832                 if (newHeader == &AS_PAREN_PAREN
00833                         || newHeader == &AS_BLPAREN_BLPAREN)
00834                     parenStack->back()--;
00835 
00836                 currentChar = (*newHeader)[newHeader->length() - 1];
00837                 // pad after operator
00838                 // but do not pad after a '-' that is a unary-minus.
00839                 if ( shouldPad && !(newHeader == &AS_MINUS && isUnaryMinus()) )
00840                     appendSpacePad();
00841 
00842                 previousOperator = newHeader;
00843                 continue;
00844             }
00845         }
00846         if (shouldPadParenthesies) {
00847             if (currentChar == '(' || currentChar == '[' ) {
00848                 char peekedChar = peekNextChar();
00849 
00850                 isInPotentialCalculation = true;
00851                 appendCurrentChar();
00852                 if (!(currentChar == '(' && peekedChar == ')')
00853                         && !(currentChar == '[' && peekedChar == ']'))
00854                     appendSpacePad();
00855                 continue;
00856             } else if (currentChar == ')' || currentChar == ']') {
00857                 char peekedChar = peekNextChar();
00858 
00859                 if (!(previousChar == '(' && currentChar == ')')
00860                         && !(previousChar == '[' && currentChar == ']'))
00861                     appendSpacePad();
00862 
00863                 appendCurrentChar();
00864 
00865                 if (peekedChar != ';' && peekedChar != ',' && peekedChar != '.'
00866                         && !(currentChar == ']' && peekedChar == '['))
00867                     appendSpacePad();
00868                 continue;
00869             }
00870         }
00871 
00872         appendCurrentChar();
00873     }
00874 
00875     // return a beautified (i.e. correctly indented) line.
00876 
00877     string beautifiedLine;
00878     int readyFormattedLineLength = trim(readyFormattedLine).length();
00879 
00880     if (prependEmptyLine
00881             && readyFormattedLineLength > 0
00882             && previousReadyFormattedLineLength > 0) {
00883         isLineReady = true; // signal that a readyFormattedLine is still waiting
00884         beautifiedLine = beautify("");
00885     } else {
00886         isLineReady = false;
00887         beautifiedLine = beautify(readyFormattedLine);
00888     }
00889 
00890     prependEmptyLine = false;
00891     previousReadyFormattedLineLength = readyFormattedLineLength;
00892 
00893     return beautifiedLine;
00894 
00895 }
00896 
00897 
00903 bool ASFormatter::hasMoreLines() const {
00904     if (!isFormattingEnabled())
00905         return ASBeautifier::hasMoreLines();
00906     else
00907         return !endOfCodeReached;
00908 }
00909 
00915 bool ASFormatter::isFormattingEnabled() const {
00916     return (bracketFormatMode != NONE_MODE
00917             || shouldPadOperators
00918             || shouldConvertTabs);
00919 }
00920 
00930 void ASFormatter::setBracketFormatMode(BracketMode mode) {
00931     bracketFormatMode = mode;
00932 }
00933 
00943 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state) {
00944     shouldBreakClosingHeaderBrackets = state;
00945 }
00946 
00955 void ASFormatter::setBreakElseIfsMode(bool state) {
00956     shouldBreakElseIfs = state;
00957 }
00958 
00967 void ASFormatter::setOperatorPaddingMode(bool state) {
00968     shouldPadOperators = state;
00969 }
00970 
00979 void ASFormatter::setParenthesisPaddingMode(bool state) {
00980     shouldPadParenthesies = state;
00981 }
00982 
00988 void ASFormatter::setBreakOneLineBlocksMode(bool state) {
00989     shouldBreakOneLineBlocks = state;
00990 }
00991 
00997 void ASFormatter::setSingleStatementsMode(bool state) {
00998     shouldBreakOneLineStatements = state;
00999 }
01000 
01006 void ASFormatter::setTabSpaceConversionMode(bool state) {
01007     shouldConvertTabs = state;
01008 }
01009 
01010 
01016 void ASFormatter::setBreakBlocksMode(bool state) {
01017     shouldBreakBlocks = state;
01018 }
01019 
01025 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state) {
01026     shouldBreakClosingHeaderBlocks = state;
01027 }
01028 
01035 bool ASFormatter::isSequenceReached(const string &sequence) const {
01036     return currentLine.COMPARE(charNum, sequence.length(), sequence) == 0;
01037 
01038 }
01039 
01045 void ASFormatter::goForward(int i) {
01046     while (--i >= 0)
01047         getNextChar();
01048 }
01049 
01055 char ASFormatter::peekNextChar() const {
01056     int peekNum = charNum + 1;
01057     int len = currentLine.length();
01058     char ch = ' ';
01059 
01060     while (peekNum < len) {
01061         ch = currentLine[peekNum++];
01062         if (!isWhiteSpace(ch))
01063             return ch;
01064     }
01065 
01066     if (shouldConvertTabs && ch == '\t')
01067         ch = ' ';
01068 
01069     return ch;
01070 }
01071 
01077 bool ASFormatter::isBeforeComment() const {
01078     int peekNum = charNum + 1;
01079     int len = currentLine.length();
01080     // char ch = ' ';
01081     bool foundComment = false;
01082 
01083     for (peekNum = charNum + 1;
01084             peekNum < len && isWhiteSpace(currentLine[peekNum]);
01085             ++peekNum)
01086         ;
01087 
01088     if (peekNum < len)
01089         foundComment = ( currentLine.COMPARE(peekNum, 2, AS_OPEN_COMMENT) == 0
01090                          || currentLine.COMPARE(peekNum, 2, AS_OPEN_LINE_COMMENT) == 0 );
01091 
01092     return foundComment;
01093 }
01094 
01101 bool ASFormatter::getNextChar() {
01102     isInLineBreak = false;
01103     bool isAfterFormattedWhiteSpace = false;
01104 
01105     if (shouldPadOperators && !isInComment && !isInLineComment
01106             && !isInQuote && !doesLineStartComment && !isInPreprocessor
01107             && !isBeforeComment()) {
01108         int len = formattedLine.length();
01109         if (len > 0 && isWhiteSpace(formattedLine[len-1]))
01110             isAfterFormattedWhiteSpace = true;
01111     }
01112 
01113     previousChar = currentChar;
01114     if (!isWhiteSpace(currentChar)) {
01115         previousNonWSChar = currentChar;
01116         if (!isInComment && !isInLineComment && !isInQuote
01117                 && !isSequenceReached(AS_OPEN_COMMENT)
01118                 && !isSequenceReached(AS_OPEN_LINE_COMMENT) )
01119             previousCommandChar = previousNonWSChar;
01120     }
01121 
01122     int currentLineLength = currentLine.length();
01123 
01124     if (charNum+1 < currentLineLength
01125             && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment)) {
01126         currentChar = currentLine[++charNum];
01127         if (isAfterFormattedWhiteSpace)
01128             while (isWhiteSpace(currentChar) && charNum+1 < currentLineLength)
01129                 currentChar = currentLine[++charNum];
01130 
01131         if (shouldConvertTabs && currentChar == '\t')
01132             currentChar = ' ';
01133 
01134         return true;
01135     } else {
01136         if (sourceIterator->hasMoreLines()) {
01137             currentLine = sourceIterator->nextLine();
01138             if (currentLine.length() == 0) {
01139                 /*think*/ currentLine = string(" ");
01140             }
01141 
01142             // unless reading in the first line of the file,
01143             // break a new line.
01144             if (!isVirgin)
01145                 isInLineBreak = true;
01146             else
01147                 isVirgin = false;
01148 
01149             if (isInLineComment)
01150                 isImmediatelyPostLineComment = true;
01151             isInLineComment = false;
01152 
01153             trimNewLine();
01154             currentChar = currentLine[charNum];
01155 
01156             // check if is in preprocessor right after the line break and line trimming
01157             if (previousNonWSChar != '\\')
01158                 isInPreprocessor = false;
01159 
01160             if (shouldConvertTabs && currentChar == '\t')
01161                 currentChar = ' ';
01162 
01163             return true;
01164         } else {
01165             endOfCodeReached = true;
01166             return false;
01167         }
01168     }
01169 }
01170 
01175 void ASFormatter::trimNewLine() {
01176     int len = currentLine.length();
01177     charNum = 0;
01178 
01179     if (isInComment || isInPreprocessor)
01180         return;
01181 
01182     while (isWhiteSpace(currentLine[charNum]) && charNum+1 < len)
01183         ++charNum;
01184 
01185     doesLineStartComment = false;
01186     if (isSequenceReached(string("/*"))) {
01187         charNum = 0;
01188         doesLineStartComment = true;
01189     }
01190 }
01191 
01202 void ASFormatter::appendChar(char ch, bool canBreakLine) {
01203     if (canBreakLine && isInLineBreak)
01204         breakLine();
01205     formattedLine.append(1, ch);
01206 }
01207 
01217 void ASFormatter::appendCurrentChar(bool canBreakLine) {
01218     appendChar(currentChar, canBreakLine);
01219 }
01220 
01231 void ASFormatter::appendSequence(const string &sequence, bool canBreakLine) {
01232     if (canBreakLine && isInLineBreak)
01233         breakLine();
01234     formattedLine.append(sequence);
01235 }
01236 
01241 void ASFormatter::appendSpacePad() {
01242     int len = formattedLine.length();
01243     if (len == 0 || !isWhiteSpace(formattedLine[len-1]))
01244         formattedLine.append(1, ' ');
01245 }
01246 
01250 void ASFormatter::breakLine() {
01251     isLineReady = true;
01252     isInLineBreak = false;
01253 
01254     // queue an empty line prepend request if one exists
01255     prependEmptyLine = isPrependPostBlockEmptyLineRequested;
01256 
01257     readyFormattedLine =  formattedLine;
01258     if (isAppendPostBlockEmptyLineRequested) {
01259         isAppendPostBlockEmptyLineRequested = false;
01260         isPrependPostBlockEmptyLineRequested = true;
01261     } else {
01262         isPrependPostBlockEmptyLineRequested = false;
01263     }
01264 
01265     formattedLine = "";
01266 }
01267 
01279 BracketType ASFormatter::getBracketType() const {
01280     BracketType returnVal;
01281 
01282     if (foundPreDefinitionHeader)
01283         returnVal = DEFINITION_TYPE;
01284     else {
01285         bool isCommandType;
01286         isCommandType = ( foundPreCommandHeader
01287                           || ( currentHeader != NULL && isNonParenHeader )
01288                           || ( previousCommandChar == ')' )
01289                           || ( previousCommandChar == ':' && !foundQuestionMark )
01290                           || ( previousCommandChar == ';' )
01291                           || ( ( previousCommandChar == '{' ||  previousCommandChar == '}')
01292                                && isPreviousBracketBlockRelated ) );
01293 
01294         returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
01295     }
01296 
01297     if (isOneLineBlockReached())
01298         returnVal = (BracketType) (returnVal | SINGLE_LINE_TYPE);
01299 
01300     return returnVal;
01301 }
01302 
01311 bool ASFormatter::isPointerOrReference() const {
01312     bool isPR;
01313     isPR = ( !isInPotentialCalculation
01314              || IS_A(bracketTypeStack->back(), DEFINITION_TYPE)
01315              || (!isLegalNameChar(previousNonWSChar)
01316                  && previousNonWSChar != ')'
01317                  && previousNonWSChar != ']')
01318            );
01319 
01320     if (!isPR) {
01321         char nextChar = peekNextChar();
01322         isPR |= (!isWhiteSpace(nextChar)
01323                  && nextChar != '-'
01324                  && nextChar != '('
01325                  && nextChar != '['
01326                  && !isLegalNameChar(nextChar));
01327     }
01328 
01329     return isPR;
01330 }
01331 
01332 
01341 bool ASFormatter::isUnaryMinus() const {
01342     return ( (previousOperator == &AS_RETURN || !isalnum(previousCommandChar))
01343              && previousCommandChar != '.'
01344              && previousCommandChar != ')'
01345              && previousCommandChar != ']' );
01346 }
01347 
01348 
01357 bool ASFormatter::isInExponent() const {
01358     int formattedLineLength = formattedLine.length();
01359     if (formattedLineLength >= 2) {
01360         char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
01361         char prevFormattedChar = formattedLine[formattedLineLength - 1];
01362 
01363         return ( (prevFormattedChar == 'e' || prevFormattedChar == 'E')
01364                  && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)) );
01365     } else
01366         return false;
01367 }
01368 
01376 bool ASFormatter::isOneLineBlockReached() const {
01377     bool isInComment = false;
01378     bool isInQuote = false;
01379     int bracketCount = 1;
01380     int currentLineLength = currentLine.length();
01381     int i = 0;
01382     char ch = ' ';
01383     char quoteChar = ' ';
01384 
01385     for (i = charNum + 1; i < currentLineLength; ++i) {
01386         ch = currentLine[i];
01387 
01388         if (isInComment) {
01389             if (currentLine.COMPARE(i, 2, "*/") == 0) {
01390                 isInComment = false;
01391                 ++i;
01392             }
01393             continue;
01394         }
01395 
01396         if (ch == '\\') {
01397             ++i;
01398             continue;
01399         }
01400 
01401         if (isInQuote) {
01402             if (ch == quoteChar)
01403                 isInQuote = false;
01404             continue;
01405         }
01406 
01407         if (ch == '"' || ch == '\'') {
01408             isInQuote = true;
01409             quoteChar = ch;
01410             continue;
01411         }
01412 
01413         if (currentLine.COMPARE(i, 2, "//") == 0)
01414             break;
01415 
01416         if (currentLine.COMPARE(i, 2, "/*") == 0) {
01417             isInComment = true;
01418             ++i;
01419             continue;
01420         }
01421 
01422         if (ch == '{')
01423             ++bracketCount;
01424         else if (ch == '}')
01425             --bracketCount;
01426 
01427         if(bracketCount == 0)
01428             return true;
01429     }
01430 
01431     return false;
01432 }
01433 
01434 
01443 const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry) {
01444     return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry);
01445 }
01446 
01447 
01448 
01449 #ifdef USES_NAMESPACE
01450 }
01451 #endif
01452 
01453 
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:34 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003