KDevelop API Documentation

lib/astyle/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.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:47 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003