Update of /cvsroot/cpptool/rfta/bin/testdata/rfta In directory sc8-pr-cvs1:/tmp/cvs-serv10001/bin/testdata/rfta Added Files: ASTDumper.cpp CPPParser.cpp DeclarativeCondition.cpp ForDeclaration.cpp HTMLWriter.cpp KeyedString.h Main.cpp VariableDeclMutator.cpp Log Message: * moved test source to testdata/rfta --- NEW FILE: ASTDumper.cpp --- // ////////////////////////////////////////////////////////////////////////// // Implementation file ASTDumper.cpp for class ASTDumper // (c)Copyright 2000, Baptiste Lepilleur. // Created: 2002/10/20 // ////////////////////////////////////////////////////////////////////////// #include "ASTDumper.h" #include "HTMLWriter.h" #include <boost/format.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/operations.hpp> #include <rfta/MaxLODMutator.h> #include <rfta/NonSemanticBlanker.h> #include <rfta/ParseContext.h> #include <rfta/ParserError.h> #include <rfta/SourceASTNode.h> #include <rfta/StatementsParser.h> namespace Refactoring { class ASTDumpVisitor : public ASTNodePropertyVisitor , public ASTNodeVisitor { public: ASTDumpVisitor( HTMLWriter &writer, const SourceASTNodePtr &source ); void visitProperty( const std::string &propertyName, const ASTNodePtr &propertyNode ); void visitNode( const ASTNodePtr &node ); private: HTMLWriter &writer_; SourceASTNodePtr sourceAST_; ASTNodePtr currentNode_; }; ASTDumpVisitor::ASTDumpVisitor( HTMLWriter &writer, const SourceASTNodePtr &source ) : writer_( writer ) , sourceAST_( source ) { } void ASTDumpVisitor::visitProperty( const std::string &propertyName, const ASTNodePtr &propertyNode ) { { HTMLWriter::Tagger row1Tagger( "TR", writer_.getStream(), "ALIGN=LEFT", HTMLWriter::newLine ); HTMLWriter::Tagger propertyTagger( "TD", writer_.getStream(), "COLSPAN=\"2\"" ); writer_.writeBold( "Property: " ); writer_.write( propertyName ); } HTMLWriter::Tagger row1Tagger( "TR", writer_.getStream(), "ALIGN=LEFT", HTMLWriter::newLine ); HTMLWriter::Tagger cell1Tagger( "TD", writer_.getStream(), "WIDTH=24 BGCOLOR=Navy", HTMLWriter::newLine ); cell1Tagger.end(); HTMLWriter::Tagger cell2Tagger( "TD", writer_.getStream(), "", HTMLWriter::newLine ); visitNode( propertyNode ); cell2Tagger.end(); } void ASTDumpVisitor::visitNode( const ASTNodePtr &node ) { HTMLWriter::Tagger tableTagger( "TABLE", writer_.getStream(), "WIDTH=\"100%\" BORDER=0 COLS=2", HTMLWriter::newLine ); { // Node type HTMLWriter::Tagger row1Tagger( "TR", writer_.getStream(), "ALIGN=LEFT", HTMLWriter::newLine ); HTMLWriter::Tagger typeTagger( "TD", writer_.getStream(), "COLSPAN=\"2\"" ); writer_.writeBold( "Type: " ); writer_.write( node->getType() ); writer_.lineBreak(); writer_.writePreformated( node->getOriginalText() ); } // Properties node->visitProperties( *this ); for ( int childIndex =0; childIndex < node->getChildCount(); ++childIndex ) { { HTMLWriter::Tagger row1Tagger( "TR", writer_.getStream(), "ALIGN=LEFT", HTMLWriter::newLine ); HTMLWriter::Tagger typeTagger( "TD", writer_.getStream(), "COLSPAN=\"2\"" ); std::string heading = (boost::format( "Child[%1%]" ) % (childIndex+1) ).str(); writer_.writeBold( heading ); } HTMLWriter::Tagger row2Tagger( "TR", writer_.getStream(), "ALIGN=LEFT", HTMLWriter::newLine ); HTMLWriter::Tagger cell1Tagger( "TD", writer_.getStream(), "WIDTH=24 BGCOLOR=Navy", HTMLWriter::newLine ); cell1Tagger.end(); HTMLWriter::Tagger cell2Tagger( "TD", writer_.getStream(), "", HTMLWriter::newLine ); visitNode( node->getChildAt( childIndex ) ); cell2Tagger.end(); } } ASTDumper::ASTDumper() { } ASTDumper::~ASTDumper() { } void ASTDumper::dump( const std::string &source, const boost::filesystem::path &logDir, const std::string &title ) { boost::filesystem::path filePath = makeUniquePath( logDir ); boost::filesystem::ofstream stream( filePath ); HTMLWriter writer( stream ); writer.writeHeader( title ); writer.writeH2( "Source:" ); writer.writePreformated( source ); writer.writeH2( "Abstract syntax tree:" ); writeAST( source, writer ); writer.writeFooter(); stream.close(); } const boost::filesystem::path ASTDumper::makeUniquePath( const boost::filesystem::path &logDir ) { int serialNo = 1; while ( true ) { std::string fileName = (boost::format( "dump-%05d.html" ) % serialNo).str(); boost::filesystem::path filePath = logDir << fileName; if ( !boost::filesystem::exists( filePath ) ) return filePath; ++serialNo; } } void ASTDumper::writeAST( const std::string &source, HTMLWriter &writer ) { NullPPDirectiveListener nullListener; std::string blankedSource; NonSemanticBlanker blanker( source, blankedSource, nullListener ); blanker.blank(); SourceASTNodePtr sourceAST = SourceASTNode::create( blankedSource, source ); ParseContext context( sourceAST ); StatementsParser parser( context, sourceAST->getBlankedSourceStart(), sourceAST->getBlankedSourceEnd() ); try { if ( !parser.tryParse() ) writer.writeError( "Failed to parse top-level statements." ); MaxLODMutator mutator; mutator.mutate( sourceAST, sourceAST ); ASTDumpVisitor visitor( writer, sourceAST ); visitor.visitNode( sourceAST ); } catch ( ParserError &e ) { writer.writeError( "Parsing failed:" ); writer.writePreformated( e.what() ); } } } // namespace Refactoring --- NEW FILE: CPPParser.cpp --- #include "stdafx.h" #include <rfta/parser/CPPParser.h> #include <rfta/parser/NonSemanticBlanker.h> #include <rfta/parser/MaxLODMutator.h> #include <rfta/parser/DeclarationListParser.h> #include <rfta/parser/ParseContext.h> #include <rfta/parser/ParserError.h> #include <rfta/parser/ASTNodeAndPropertyVisitor.h> #include <rfta/parser/ASTNodes.h> namespace Refactoring { namespace { class FunctionImplementationVisitor : public ASTNodeAndPropertyVisitor { public: FunctionImplementationVisitor( int functionBodyPosition ) : functionBodyPosition_( functionBodyPosition ) , foundFunction_( false ) { } ASTNodePtr findFunctionImplementation( const ASTNodePtr &node ) { visitNode( node ); if ( !foundFunction_ ) return ASTNodePtr(); return functionImplementationNode_; } protected: // overridden from ASTNodeAndPropertyVisitor bool canSkipNode( const ASTNodePtr &node ) const { return foundFunction_; } bool needsToVisitProperties( const ASTNodePtr &node ) const { return !foundFunction_; } bool needsToVisitChildren( const ASTNodePtr &node ) const { return node->getType().hasSomeFeatureOf( ASTNodeTypeFeatures::mayHaveFunctionImplChildren ); } bool needsToHandleNode( const ASTNodePtr& node ) const { return node->getType() == ASTNodeTypes::functionImplementation && !foundFunction_; } void handleNode( const ASTNodePtr& node ) { if ( node->getRange().contains( SourceRange( functionBodyPosition_,0 ) ) ) { foundFunction_ = true; functionImplementationNode_ = node; } } private: bool foundFunction_; int functionBodyPosition_; ASTNodePtr functionImplementationNode_; }; } CPPParser::CPPParser( const std::string &source ) { NullPPDirectiveListener nullListener; std::string blankedSource; NonSemanticBlanker blanker( source, blankedSource, nullListener ); blanker.blank(); sourceNode_ = SourceASTNode::create( blankedSource, source ); } SourceASTNodePtr CPPParser::getSourceNode() const { return sourceNode_; } ASTNodePtr CPPParser::parseForFunctionBodyAt( int position ) { parseAll(); FunctionImplementationVisitor visitor( position ); return visitor.findFunctionImplementation( sourceNode_ ); } void CPPParser::parseForFunctionDeclarations() { parseAll(); } void CPPParser::parseAll() { ParseContext context( sourceNode_ ); DeclarationListParser parser( context, sourceNode_->getBlankedSourceStart(), sourceNode_->getBlankedSourceEnd() ); if ( !parser.tryParse() ) throw ParserError( "top level source file parsing failed.", context ); MaxLODMutator mutator; mutator.mutate( sourceNode_, sourceNode_ ); } */ } // namespace Refactoring --- NEW FILE: DeclarativeCondition.cpp --- { if ( int x = 3 ) ; while ( char c = next() ) ; switch ( char token = nextToken() ) { default: } for ( int count =0; count < maxCount; ++count ) ; } --- NEW FILE: ForDeclaration.cpp --- { for ( int a, b;; ) //int a, b;; ) ; } --- NEW FILE: HTMLWriter.cpp --- // ////////////////////////////////////////////////////////////////////////// // Implementation file HTMLWriter.cpp for class HTMLWriter // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2002/10/20 // ////////////////////////////////////////////////////////////////////////// #include "HTMLWriter.h" #include <iostream> #include <string> namespace Refactoring { HTMLWriter::Tagger::Tagger( const std::string &tagName, std::ostream &stream, const std::string &attributes, EOLType eolType ) : tagName_( tagName ) , stream_( stream ) , tagClosed_( false ) , eolType_( eolType ) { stream_ << "<" << tagName_; if ( !attributes.empty() ) stream_ << " " << attributes; stream_ << ">"; if ( eolType_ == newLine ) stream_ << "\n"; } HTMLWriter::Tagger::~Tagger() { end(); } void HTMLWriter::Tagger::end() { if ( tagClosed_ ) return; tagClosed_ = true; stream_ << "</" << tagName_ << ">"; if ( eolType_ == newLine ) stream_ << "\n"; } HTMLWriter::HTMLWriter( std::ostream &stream ) : stream_( stream ) { } HTMLWriter::~HTMLWriter() { } void HTMLWriter::writeHeader( const std::string &title ) { stream_ << "<HTML>"; Tagger headTagger( "HEAD", stream_, "", newLine ); Tagger titleTagger( "TITLE", stream_ ); write( title ); titleTagger.end(); headTagger.end(); stream_ << "<BODY>\n"; } void HTMLWriter::writeFooter() { stream_ << "</BODY>\n"; stream_ << "</HTML>\n"; } void HTMLWriter::write( const std::string &text ) { for ( int index =0; index < text.length(); ++index ) { char c = text[index]; std::string escaped; switch ( c ) { case '<': escaped = "<"; break; case '>': escaped = ">"; break; case '&': escaped = "&"; break; // case '\'': escaped = "'"; break; case '"': escaped = """; break; case ' ': escaped = ' '; break; default: escaped = c; break; } stream_ << escaped; } } void HTMLWriter::writeH2( const std::string &heading ) { Tagger tagger( "H2", stream_, "", newLine ); write( heading ); } void HTMLWriter::writePreformated( const std::string &text ) { Tagger tagger( "PRE", stream_, "", newLine ); write( text ); } void HTMLWriter::writeError( const std::string &text ) { Tagger tagger( "P", stream_, "color=\"#ff0000\"" ); write( text ); } void HTMLWriter::writeBold( const std::string &text ) { Tagger tagger( "B", stream_, "" ); write( text ); } void HTMLWriter::lineBreak() { stream_ << "<BR>" << std::endl; } std::ostream & HTMLWriter::getStream() const { return stream_; } } // namespace Refactoring --- NEW FILE: KeyedString.h --- // ////////////////////////////////////////////////////////////////////////// // (c)Copyright 2003, Andre Baresel // Created: 2003/04/28 // ////////////////////////////////////////////////////////////////////////// #ifndef RFTA_KEYEDSTRING_H #define RFTA_KEYEDSTRING_H #include <vector> #include <map> #include <string> namespace Refactoring { namespace Testing { class KeyedString { public: KeyedString& operator<< (std::string characters); operator std::string () const; KeyedString& addKeyed (std::string key , std::string word ); std::string asString() const; std::vector<int> getKeyedIndex(std::string key) const; std::vector<int> getKeyedLen(std::string key) const; int getKeyedIndex(std::string key,int index) const; int getKeyedLen(std::string key,int index) const; std::string getWord(std::string key, int index) const; int length() const; KeyedString& setKeyStart(std::string key); KeyedString& setKeyEnd(std::string key); protected: std::string sequence_; std::map<std::string,std::vector<int> > wordIndex_; std::map<std::string,std::vector<int> > wordLen_; std::map<std::string,std::vector<std::string> > word_; }; // INLINED MEMBERS: inline KeyedString& KeyedString::operator<<(std::string characters) { sequence_.append(characters); return *this; } inline KeyedString::operator std::string() const { return sequence_; } inline std::string KeyedString::asString() const { return sequence_; } inline std::vector<int> KeyedString::getKeyedIndex(std::string key) const { std::map<std::string,std::vector<int> >::const_iterator it; it = wordIndex_.find(key); if (it == wordIndex_.end()) return std::vector<int>(); return (*it).second; } inline std::vector<int> KeyedString::getKeyedLen(std::string key) const { std::map<std::string,std::vector<int> >::const_iterator it; it = wordLen_.find(key); if (it == wordLen_.end()) return std::vector<int>(); return (*it).second; } inline int KeyedString::getKeyedIndex(std::string key, int index) const { std::map<std::string,std::vector<int> >::const_iterator it; it = wordIndex_.find(key); if (it == wordIndex_.end()) throw std::logic_error("No string registered for this key."); if ((*it).second.size()<index) throw std::logic_error("Index out of range."); return (*it).second[index]; } inline int KeyedString::getKeyedLen(std::string key, int index) const { std::map<std::string,std::vector<int> >::const_iterator it; it = wordLen_.find(key); if (it == wordLen_.end()) throw std::logic_error("No string registered for this key."); if ((*it).second.size()<index) throw std::logic_error("Index out of range."); return (*it).second[index]; } inline std::string KeyedString::getWord(std::string key, int index) const { std::map<std::string,std::vector<std::string> >::const_iterator it; it = word_.find(key); if (it == word_.end()) throw std::logic_error("No string registered for this key."); if ((*it).second.size() < index) throw std::logic_error("Index out of range."); return ((*it).second)[index]; } inline KeyedString& KeyedString::addKeyed(std::string key,std::string word) { wordIndex_[key].push_back(sequence_.length()); wordLen_[key].push_back(word.length()); word_[key].push_back(word); sequence_.append(word); return *this; } inline int KeyedString::length() const { return sequence_.length(); } inline KeyedString& KeyedString::setKeyStart(std::string key) { wordIndex_[key].push_back(sequence_.length()); wordLen_[key].push_back(0); word_[key].push_back(""); return *this; } inline KeyedString& KeyedString::setKeyEnd(std::string key) { std::vector<int>& v1_ref = wordIndex_[key]; std::vector<int>& v2_ref = wordLen_[key]; if ( v1_ref.empty() || v2_ref.empty() || v2_ref.size() != v1_ref.size() ) throw std::logic_error("Key was not initialized correctly."); int idx = v1_ref.size()-1; v2_ref[idx] = sequence_.length() - v1_ref[idx]; return *this; } } // namespace Testing } // namespace Refactoring #endif // RFTA_KEYEDSTRING_H --- NEW FILE: Main.cpp --- #include "ASTDumper.h" #include <boost/lexical_cast.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/path.hpp> #include <iostream> #include <stdexcept> #include <string> static void printUsage() { std::cout << "ASTDump Usage:\n" "ASTDump firstLine lastLine filePath [outputDirectory]\n" "\n" "ASTDump will dump the AST of the specified file range in an HTML\n" "file located in the specified directory. Default for ouput duirectory\n" "is ./astdump.\n" "\n" "Warning: the outputDirectory must exist!" ; } int main( int argc, char *argv[] ) { if ( argc < 4 || argc > 5 ) { printUsage(); return 1; } else { try { int firstLineNumber = boost::lexical_cast<int>( argv[1] ); int lastLineNumber = boost::lexical_cast<int>( argv[2] ); boost::filesystem::path path( argv[3], boost::filesystem::system_specific ); std::string outputPathName = "astdump"; if ( argc == 5 ) outputPathName = argv[4]; boost::filesystem::path outputPath( outputPathName, boost::filesystem::system_specific ); boost::filesystem::ifstream stream( path ); int currentLineNumber = 1; while ( currentLineNumber < firstLineNumber ) { std::string discard; std::getline( stream, discard ); ++currentLineNumber; } std::string source; while ( currentLineNumber <= lastLineNumber ) { std::string line; std::getline( stream, line ); source += line; source += '\n'; ++currentLineNumber; } Refactoring::ASTDumper dumper; dumper.dump( source, outputPath, path.generic_path() ); } catch ( std::exception &e ) { std::cerr << "Fatal error:\n" << "Unexpected exception of type " << typeid(e).name() << std::endl << e.what() << std::endl; return 2; } } return 0; } --- NEW FILE: VariableDeclMutator.cpp --- // ////////////////////////////////////////////////////////////////////////// // Implementation file VariableDeclMutator.cpp for class VariableDeclMutator // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2002/10/16 // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ExpressionASTNode.h" #include <rfta/ParseContext.h> #include "StatementASTNode.h" #include "VariableDeclMutator.h" #include <boost/format.hpp> namespace Refactoring { /// @todo baptiste The declaration 'struct time_t stamp' is not parsed as a variable declaration. /// @todo baptiste Variable type are not allowed to contains number. VariableDeclMutator::VariableDeclMutator( ParseContext &context, const char *start, const char *end, const ASTNodePtr &node ) : Parser( context, start, end ) , node_( node ) { Tracker tracker( "VariableDeclMutator::VariableDeclMutator", *this ); if ( node_->getType() != StatementASTNode::declarationOrExpressionStatement ) throwFailure( "Bad node type: " + node_->getType() ); } VariableDeclMutator::~VariableDeclMutator() { } // - find the first occurence of either '=', ',' or ';'. The variable // declaration is before it. // - backtracking, skip over pairs of [], and capture (=> this is the type // suffix) // - backtracking, capture the identifier, this is the local variable name // - capture everything before the identifer, this is the type prefix of the // local variable. // - check that the captured type is valid: // - type does not contains characters others then id letters, "&* " and // :: outside of template parameters (skipping over <...>). // - type is not a keyword that may come before an identifier (new, sizeof) // (there might be other, we'll find out the hard way). /// @todo baptiste Capture initialization value ( =... ) and iterates over /// the list of declaration ( int x, y, z; ) bool VariableDeclMutator::tryMutate() { Tracker tracker( "VariableDeclMutator::tryMutate", *this ); const char *separatorPos = findFirstSeparatorBalancingTemplateBrackets( start_, end_ ); if ( separatorPos == end_ ) return false; /// @todo baptiste This should never happen, since ';' should at least be there current_ = separatorPos; backtrackSkippingSpaces(); int suffixEndIndex = getCurrentIndex(); if ( !backtrackSkippingOverArrayBrackets() ) return false; backtrackSkippingSpaces(); int suffixStartIndex = getCurrentIndex(); if ( !backtrackSkippingOverVariableIdentifier() ) return false; if ( current_ == start_ ) // no type before identifier ! return false; int prefixEndIndex = getCurrentIndex(); const char *prefixEnd = current_; current_ = start_; if ( !isValidTypePrefix( prefixEnd ) ) return false; current_ = separatorPos; // ok this is a valid variable declaration... node_->mutateType( StatementASTNode::declarationStatement ); node_->removeAllProperties(); ASTNodePtr variableDeclNode = addNodeVariableDecl( node_, prefixEndIndex, // prefix end prefixEndIndex, // secondary prefix start prefixEndIndex, // variable name start suffixStartIndex, suffixEndIndex ); // from now, throw parse failure if unexpected stuff happen continueParse( variableDeclNode, prefixEndIndex ); return true; } ASTNodePtr VariableDeclMutator::addNodeVariableDecl( const ASTNodePtr &declStatement, int prefixEnd, int secondaryPrefixStart, int variableNameStart, int suffixStart, int suffixEnd ) { ASTNodePtr variableDeclNode = ASTNode::create( ExpressionASTNode::variableDeclExpression, declStatement, getStartIndex(), suffixEnd - getStartIndex() ); // the correct length is set when the initializer is added. declStatement->addChild( variableDeclNode ); ASTNodePtr variableNameNode = ASTNode::create( ExpressionASTNode::variableNameExpression, variableDeclNode, variableNameStart, suffixStart - variableNameStart ); variableDeclNode->setPropertyNode( StatementASTNode::variableNameProperty, variableNameNode ); ASTNodePtr typePrefixNode = ASTNode::create( ExpressionASTNode::typeDeclPrefixExpression, variableDeclNode, getStartIndex(), prefixEnd - getStartIndex() ); variableDeclNode->setPropertyNode( StatementASTNode::typeDeclPrefixProperty, typePrefixNode ); if ( variableNameStart - secondaryPrefixStart > 0 ) { ASTNodePtr secondaryTypePrefixNode = ASTNode::create( ExpressionASTNode::typeDeclPrefixExpression, variableDeclNode, secondaryPrefixStart, variableNameStart - secondaryPrefixStart ); variableDeclNode->setPropertyNode( StatementASTNode::typeDeclSecondaryPrefixProperty, secondaryTypePrefixNode ); } if ( suffixEnd - suffixStart > 0 ) { ASTNodePtr suffixNode = ASTNode::create( ExpressionASTNode::typeDeclSuffixExpression, variableDeclNode, suffixStart, suffixEnd - suffixStart ); variableDeclNode->setPropertyNode( StatementASTNode::typeDeclSuffixProperty, suffixNode ); } return variableDeclNode; } bool VariableDeclMutator::backtrackSkippingOverArrayBrackets() { while ( hasPrevious() && current_[-1] == ']' ) { --current_; if ( !hasPrevious() ) return false; // missing '[' ! while ( *current_ != '[' ) { --current_; if ( !hasPrevious() ) return false; // missing '[' ! } } return hasPrevious(); } bool VariableDeclMutator::backtrackSkippingOverVariableIdentifier() { if ( !hasPrevious() ) return false; const char *identifierEnd = current_; --current_; while ( hasPrevious() && isIdentifierLetter( *current_ ) ) --current_; if ( !hasPrevious() ) return false; ++current_; if ( current_ == identifierEnd ) return false; return isValidIdentifierFirstLetter( *current_ ); } bool VariableDeclMutator::isValidTypePrefix( const char *prefixEnd ) { const char *it = start_; while ( it != prefixEnd ) { if ( *it == '<' ) { if ( !tryFindNextBalanced( it, prefixEnd ) ) return false; continue; } if ( *it == ':' ) // only :: is valid { ++it; if ( it == prefixEnd || *it != ':' ) return false; ++it; continue; } if ( isBadTypeChar( *it++ ) ) return false; } return isNotKeyword( std::string( start_, prefixEnd ) ); } bool VariableDeclMutator::isValidSecondaryTypePrefix( const char *prefixStart, const char *prefixEnd ) { const char *current = prefixStart; while ( current != prefixEnd ) { char c = *current++; if ( !isSymbolChar( c ) || !isKeywordLetter( c ) ) return false; } return true; } bool VariableDeclMutator::tryFindNextBalanced( const char *¤t, const char *end, char opening, char closing ) { int balance = 1; while ( ++current != end ) { char c = *current; if ( c == closing ) { --balance; if ( balance == 0 ) { ++current; return true; } } else if ( c == opening ) ++balance; } return false; } inline bool VariableDeclMutator::isBadTypeChar( char c ) { return !( isIdentifierLetter(c) || isSymbolChar(c) ); } inline bool VariableDeclMutator::isSymbolChar( char c ) { static const std::string allowedSymbol( "*& " ); return allowedSymbol.find( c ) != std::string::npos; } bool VariableDeclMutator::isNotKeyword( const std::string &type ) { std::string cleanType = stripTrailingSpaces( type ); return !( cleanType == "new" || cleanType == "sizeof" ); } const char * VariableDeclMutator::findFirstSeparatorBalancingTemplateBrackets( const char *start, const char *end ) { static const std::string separators( ";,=(" ); const char *current = start; while ( current != end ) { char c = *current; if ( separators.find_first_of( c ) != std::string::npos ) return current; else if ( c == '<' ) { if ( !tryFindNextBalanced( current, end ) ) return end; } else ++current; } return end; } std::string VariableDeclMutator::stripTrailingSpaces( const std::string &str ) { int index = str.find_last_not_of( ' ' ); if ( index == std::string::npos ) return str; return str.substr( 0, index+1 ); } bool VariableDeclMutator::skipOverAssignmentInitializer() { const char *start = current_; while ( current_ != end_ ) { char c = *current_; if ( c == ';' || c == ',' ) return current_ != (start+1); else if ( c == '(' ) { if ( !tryFindNextBalanced( current_, end_, '(', ')' ) ) return false; } else if ( c == '[' ) { if ( !tryFindNextBalanced( current_, end_, '[', ']' ) ) return false; } ++current_; } return false; } bool VariableDeclMutator::skipOverConstructorInitilizer() { if ( !tryFindNextBalanced( current_, end_, '(', ')' ) ) return false; if ( current_ == end_ ) return false; return *current_ == ',' || *current_ == ';'; } void VariableDeclMutator::continueParse( const ASTNodePtr &variableDeclNode, int prefixEndIndex ) { Tracker tracker( "VariableDeclMutator::continueParse", *this ); createAndAddInitializerNode( variableDeclNode ); int variableNumber = 2; while ( current_ != end_ ) { skipSpaces(); int secondaryPrefixStartIndex = getCurrentIndex(); const char *secondaryPrefixStart = current_; const char *separatorPos = findFirstSeparatorBalancingTemplateBrackets( current_, end_ ); if ( separatorPos == end_ ) { boost::format frmt( "failed to find expected variable declaration separator " "for declaration %1%: ',;=('. " "This may be due to balancing a '<..>'."); throwFailure( frmt % variableNumber ); } current_ = separatorPos; // Parse suffix int suffixEndIndex = getCurrentIndex(); if ( !backtrackSkippingOverArrayBrackets() ) { throwFailure( boost::format( "failed to find matching opening ']' for " "variable declaration %1%." ) % variableNumber ); } int suffixStartIndex = getCurrentIndex(); if ( suffixStartIndex <= secondaryPrefixStartIndex ) { throwFailure( boost::format( "failed to find matching opening ']' for " "variable declaration %1%." ) % variableNumber ); } if ( !backtrackSkippingOverVariableIdentifier() ) { throwFailure( boost::format( "no valid identifier found for " "variable declaration %1%" ) % variableNumber ); } int secondaryPrefixEndIndex = getCurrentIndex(); const char *secondaryPrefixEnd = current_; if ( !isValidSecondaryTypePrefix( secondaryPrefixStart, secondaryPrefixEnd ) ) { std::string prefix( secondaryPrefixStart, secondaryPrefixEnd - secondaryPrefixStart ); throwFailure( boost::format( "invalid secondary type prefix for " "variable declaration %1%: %2%" ) % variableNumber % prefix ); } ASTNodePtr variableDeclNode = addNodeVariableDecl( node_, prefixEndIndex, secondaryPrefixStartIndex, secondaryPrefixEndIndex, suffixStartIndex, suffixEndIndex ); current_ = separatorPos; createAndAddInitializerNode( variableDeclNode ); ++variableNumber; } } void VariableDeclMutator::createAndAddInitializerNode( const ASTNodePtr &variableDeclNode ) { Tracker tracker( "VariableDeclMutator::createAndAddInitializerNode", *this ); int initializerStartIndex = getCurrentIndex(); int initializerValueStartIndex; int initializerValueEndIndex; std::string initializerType; if( *current_ == '=' ) { initializerType = ExpressionASTNode::assignVariableInitializerExpression; ++current_; initializerValueStartIndex = getCurrentIndex(); skipOverAssignmentInitializer(); initializerValueEndIndex = getCurrentIndex() -1; } else if ( *current_ == '(' ) { ++current_; initializerType = ExpressionASTNode::constructorVariableInitializerExpression; initializerValueStartIndex = getCurrentIndex(); findNextBalanced( '(', ')' ); initializerValueEndIndex = getCurrentIndex() -1; } else if ( *current_ == ';' || *current_ == ',' ) ++current_; else { throwFailure( boost::format("unexpected character: '%1%'.") % *current_ ); } if ( !initializerType.empty() ) { int initializerLength = getCurrentIndex() - initializerStartIndex; int variableDeclEndIndex = initializerValueEndIndex+1; variableDeclNode->setLength( variableDeclEndIndex - variableDeclNode->getStartIndex() ); ASTNodePtr initializerNode = ASTNode::create( initializerType, variableDeclNode, initializerStartIndex, initializerLength ); variableDeclNode->setPropertyNode( ExpressionASTNode::variableInitializerProperty, initializerNode ); ASTNodePtr valueNode = ASTNode::create( ExpressionASTNode::valueExpression, initializerNode, initializerValueStartIndex, initializerValueEndIndex - initializerValueStartIndex ); initializerNode->setPropertyNode( ExpressionASTNode::valueProperty, valueNode ); skipSpaces(); if ( *current_ == ';' || *current_ == ',' ) ++current_; else throwFailure( boost::format("unexpected character: '%1%'.") % *current_ ); } } } // namespace Refactoring |