From: <bl...@us...> - 2003-05-03 17:43:48
|
Update of /cvsroot/cpptool/rfta/src/rftaparser In directory sc8-pr-cvs1:/tmp/cvs-serv1937/src/rftaparser Added Files: EnumBodyParser.cpp EnumBodyParser.h EnumBodyParserTest.cpp EnumBodyParserTest.h Log Message: * new parser for enum body. Start at the { --- NEW FILE: EnumBodyParser.cpp --- // ////////////////////////////////////////////////////////////////////////// // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2003/05/02 // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "EnumBodyParser.h" #include <rfta/parser/ASTNodes.h> #include <rfta/parser/ParseContext.h> #include <rfta/parser/ParserTools.h> namespace Refactoring { EnumBodyParser::EnumBodyParser( ParseContext &context, const char *start, const char *end ) : Parser( context, start, end ) { } EnumBodyParser::~EnumBodyParser() { } void EnumBodyParser::parse() { Tracker tracker( "EnumBodyParser::tryParse", *this ); Xtl::CStringView body( findBodyRange() ); ASTNodePtr bodyNode = createASTNode( ASTNodeTypes::enumBody, getParentNode(), body ); Xtl::CStringEnumerator current( body.getStart()+1, body.getEnd()-1 ); while ( current.hasNext() ) { ParserTools::skipSpaces( current ); Xtl::CStringView identifier = ParserTools::readNextIdentifier( current ); ASTNodePtr enumConstantNode = makeEnumConstantNode( bodyNode, identifier ); parseConstantInitializer( enumConstantNode, current ); enumConstantNode->setEndIndex( getIndexOf(current) ); bodyNode->addChild( enumConstantNode ); } context_.addNode( bodyNode ); current_ = body.getEnd(); } Xtl::CStringView EnumBodyParser::findBodyRange() { skipSpaces(); Xtl::CStringView body( current_, end_ ); expect('{'); findNextBalanced('{','}'); body.setEnd( current_ ); return body; } ASTNodePtr EnumBodyParser::makeEnumConstantNode( const ASTNodePtr &bodyNode, const Xtl::CStringView &identifier ) { ASTNodePtr constantNode = createASTNode( ASTNodeTypes::enumConstant, bodyNode, identifier ); ASTNodePtr identifierNode = createASTNode( ASTNodeTypes::variableIdentifier, constantNode, identifier ); constantNode->setPropertyNode( ASTNodeProperties::variableNameProperty, identifierNode ); return constantNode; } void EnumBodyParser::parseConstantInitializer( const ASTNodePtr &enumConstantNode, Xtl::CStringEnumerator ¤t ) { Xtl::CStringView initializer( current ); if ( isInitializerEnd( current ) ) return; Xtl::CStringView value = parseInitializerValue( current, initializer ); addInitializerNodes( enumConstantNode, initializer, value ); } bool EnumBodyParser::isInitializerEnd( Xtl::CStringEnumerator ¤t ) { ParserTools::skipSpaces( current ); if ( !current.hasNext() ) return true; if ( *current != ',' ) return false; ++current; return true; } Xtl::CStringView EnumBodyParser::parseInitializerValue( Xtl::CStringEnumerator ¤t, Xtl::CStringView &initializer ) { if ( *current != '=' ) throw ParserTools::ParseError( "syntax error in enum constant declaration.", current ); ParserTools::skipSpaces( ++current ); Xtl::CStringView value( current ); Xtl::CStringBackEnumerator valueEnum; if ( !ParserTools::trySkipUntil( current, ',', ParserTools::SkipExpressionPolicy() ) ) { current.setCurrent( current.getString().getEnd() ); valueEnum = current; } else valueEnum = current - 1; initializer.setEnd( current ); ParserTools::skipSpaces( valueEnum ); value.setEnd( valueEnum ); return value; } void EnumBodyParser::addInitializerNodes( const ASTNodePtr &enumConstantNode, const Xtl::CStringView &initializer, const Xtl::CStringView &value ) { ASTNodePtr initializerNode = createASTNode( ASTNodeTypes::assignVariableInitializerExpression, enumConstantNode, initializer ); ASTNodePtr valueNode = createASTNode( ASTNodeTypes::valueExpression, initializerNode, value ); initializerNode->setPropertyNode( ASTNodeProperties::valueProperty, valueNode ); enumConstantNode->setPropertyNode( ASTNodeProperties::variableInitializerProperty, initializerNode ); } } // namespace Refactoring --- NEW FILE: EnumBodyParser.h --- // ////////////////////////////////////////////////////////////////////////// // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2003/05/02 // ////////////////////////////////////////////////////////////////////////// #ifndef RFTA_ENUMBODYPARSER_H #define RFTA_ENUMBODYPARSER_H #include <rfta/parser/Parser.h> #include <xtl/Forwards.h> namespace Refactoring { /// This class represents class RFTAPARSER_API EnumBodyParser : public Parser { public: /*! Constructs a EnumBodyParser object. */ EnumBodyParser( ParseContext &context, const char *start, const char *end ); virtual ~EnumBodyParser(); void parse(); private: Xtl::CStringView findBodyRange(); ASTNodePtr makeEnumConstantNode( const ASTNodePtr &bodyNode, const Xtl::CStringView &identifier ); void parseConstantInitializer( const ASTNodePtr &enumConstantNode, Xtl::CStringEnumerator ¤t ); Xtl::CStringView parseInitializerValue( Xtl::CStringEnumerator ¤t, Xtl::CStringView &initializer ); void addInitializerNodes( const ASTNodePtr &enumConstantNode, const Xtl::CStringView &initializer, const Xtl::CStringView &value ); bool isInitializerEnd( Xtl::CStringEnumerator ¤t ); }; // Inlines methods for EnumBodyParser: // ----------------------------------- } // namespace Refactoring #endif // RFTA_ENUMBODYPARSER_H --- NEW FILE: EnumBodyParserTest.cpp --- // ////////////////////////////////////////////////////////////////////////// // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2003/05/02 // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "EnumBodyParserTest.h" #include "EnumBodyParser.h" #include <xtl/Type.h> #include <rfta/parser/ASTNodes.h> #include <boost/lexical_cast.hpp> namespace Refactoring { namespace Testing { struct ParserAsserter : Asserter<ParserAsserter> { template<typename ParserType> SourceASTNodePtr checkParse( const std::string &source, int endIndex, Xtl::Type<ParserType> ) { SourceASTNodePtr sourceNode = SourceASTNode::create( source, source ); ParseContext context( sourceNode ); ParserType parser( context, sourceNode->getBlankedSourceStart(), sourceNode->getBlankedSourceEnd() ); parser.parse(); CppUnit::Message message( "parsing did not stop at the expected position", std::string( "using parser: " ) + typeid(ParserType).name(), "Source:\n" + source ); checkEquals( endIndex, parser.getCurrentIndex(), message ); return sourceNode; } }; #define RFTA_ASSERT_PARSER_PASS2( ParserType, source, endIndex ) \ RFTA_CUSTOM_INIT_ASSERT( ::Refactoring::Testing::ParserAsserter() ).checkParse( \ source, endIndex, Xtl::Type<ParserType>() ); } // namespace Testing RFTAPARSER_TEST_SUITE_REGISTRATION( EnumBodyParserTest ); EnumBodyParserTest::EnumBodyParserTest() { } EnumBodyParserTest::~EnumBodyParserTest() { } void EnumBodyParserTest::setUp() { source_ = ""; builder_.reset( new Testing::SourceBuilder( source_ ) ); constantNumber_ = -1; } void EnumBodyParserTest::tearDown() { source_ = ""; } void EnumBodyParserTest::checkConstants( int constantCount ) { SourceASTNodePtr source_Node = RFTA_ASSERT_PARSER_PASS2( EnumBodyParser, source_, source_.length() ); ASTNodePtr bodyNode = source_Node->getChildAt(0); RFTA_ASSERT_NODE_HAS( bodyNode, ASTNodeTypes::enumBody, 0, builder_->getSource().length() ); RFTA_ASSERT_EQUAL( constantCount, bodyNode->getChildCount() ); for ( int index =0; index < constantCount; ++index ) checkConstant( index, bodyNode->getChildAt(index) ); } void EnumBodyParserTest::checkConstant( int index, const ASTNodePtr &constantNode ) { std::string number = boost::lexical_cast<std::string>( index ); std::string constantKey = "CONSTANT" + number; std::string identifierKey = "IDENTIFIER" + number; std::string initializerKey = "INITIALIZER" + number; std::string valueKey = "VALUE" + number; RFTA_ASSERT_NODE_HAS( constantNode, ASTNodeTypes::enumConstant, builder_->getStartIndex(constantKey), builder_->getLength(constantKey) ); ASTNodePtr identifierNode = constantNode->getProperty( ASTNodeProperties::variableNameProperty ); RFTA_ASSERT_NODE_HAS( identifierNode, ASTNodeTypes::variableIdentifier, builder_->getStartIndex(identifierKey), builder_->getLength(identifierKey) ); if ( !builder_->hasKey( initializerKey ) ) CPPUNIT_ASSERT( !constantNode->hasProperty( ASTNodeProperties::variableInitializerProperty ) ); else { ASTNodePtr initializerNode = constantNode->getProperty( ASTNodeProperties::variableInitializerProperty ); CPPUNIT_ASSERT( initializerNode ); RFTA_ASSERT_NODE_HAS( initializerNode, ASTNodeTypes::assignVariableInitializerExpression, builder_->getStartIndex( initializerKey ), builder_->getLength( initializerKey ) ); ASTNodePtr valueNode = initializerNode->getProperty( ASTNodeProperties::valueProperty ); CPPUNIT_ASSERT( valueNode ); RFTA_ASSERT_NODE_HAS( valueNode, ASTNodeTypes::valueExpression, builder_->getStartIndex( valueKey ), builder_->getLength( valueKey ) ); } } void EnumBodyParserTest::beginEnumBody() { builder_->addKeyed( "{", "BODY" ); } void EnumBodyParserTest::endEnumBody() { builder_->add( "}" ); builder_->extend( "BODY" ); } std::string EnumBodyParserTest::makeKey( const std::string &prefix ) { return prefix + boost::lexical_cast<std::string>( constantNumber_ ); } void EnumBodyParserTest::addConstant( const std::string &name, bool addComma ) { ++constantNumber_; std::string constantKey = makeKey( "CONSTANT" ); builder_->mark( constantKey ); builder_->addKeyed( name, makeKey( "IDENTIFIER" ) ); if ( addComma ) builder_->add( "," ); builder_->extend( constantKey ); } void EnumBodyParserTest::addConstantValue( const std::string &name, const std::string &spacer, const std::string &value, bool addComma ) { addConstant( name, false ); std::string initializerKey = makeKey( "INITIALIZER" ); builder_->addKeyed( spacer, initializerKey ); builder_->addKeyed( value, makeKey( "VALUE" ) ); if ( addComma ) builder_->add( "," ); builder_->extend( initializerKey ); builder_->extend( makeKey( "CONSTANT" ) ); } void EnumBodyParserTest::testParseEmptyEnumBody() { source_ = "{}"; checkConstants( 0 ); } void EnumBodyParserTest::testParseOneConstant() { beginEnumBody(); addConstant( "first", false ); endEnumBody(); checkConstants( 1 ); } void EnumBodyParserTest::testParseOneConstantWithValue() { beginEnumBody(); addConstantValue( "first", " = ", "1234", false ); endEnumBody(); checkConstants( 1 ); } void EnumBodyParserTest::testParseOneConstantSkipTrailingComma() { beginEnumBody(); addConstantValue( "first", " = ", "1234" ); endEnumBody(); checkConstants( 1 ); } void EnumBodyParserTest::testParseTwoConstantWithSpaces() { beginEnumBody(); addConstant( "first" ); source_ += " "; addConstant( "two", false ); endEnumBody(); checkConstants( 2 ); } void EnumBodyParserTest::testParseThreeConstant() { beginEnumBody(); addConstant( "one" ); addConstant( "two" ); addConstant( "three", false ); endEnumBody(); checkConstants( 3 ); } void EnumBodyParserTest::testParseThreeConstantWithValue() { beginEnumBody(); addConstantValue( "one", " =", "1234" ); addConstant( "two" ); addConstantValue( "three", " = ", "one +4", false ); endEnumBody(); checkConstants( 3 ); } void EnumBodyParserTest::testParseTemplatedValue() { beginEnumBody(); addConstantValue( "value", " = ", "boost::is_convertible<int,T>::value", false ); endEnumBody(); checkConstants( 1 ); } void EnumBodyParserTest::testParseLeftShitOperatorValue() { beginEnumBody(); addConstant( "first" ); addConstantValue( "two", "=", "first << 1", false ); endEnumBody(); checkConstants( 1 ); } } // namespace Refactoring --- NEW FILE: EnumBodyParserTest.h --- // ////////////////////////////////////////////////////////////////////////// // (c)Copyright 2002, Baptiste Lepilleur. // Created: 2003/05/02 // ////////////////////////////////////////////////////////////////////////// #ifndef RFTA_ENUMBODYPARSERTEST_H #define RFTA_ENUMBODYPARSERTEST_H #include "ParserTesting.h" #include <rfta/test/SourceBuilder.h> #include <boost/shared_ptr.hpp> namespace Refactoring { /// Unit tests for EnumBodyParserTest class EnumBodyParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( EnumBodyParserTest ); CPPUNIT_TEST( testParseEmptyEnumBody ); CPPUNIT_TEST( testParseOneConstant ); CPPUNIT_TEST( testParseOneConstantWithValue ); CPPUNIT_TEST( testParseOneConstantSkipTrailingComma ); CPPUNIT_TEST( testParseTwoConstantWithSpaces ); CPPUNIT_TEST( testParseThreeConstant ); CPPUNIT_TEST( testParseThreeConstantWithValue ); CPPUNIT_TEST( testParseTemplatedValue ); // CPPUNIT_TEST( testParseLeftShitOperatorValue ); CPPUNIT_TEST_SUITE_END(); public: /*! Constructs a EnumBodyParserTest object. */ EnumBodyParserTest(); /// Destructor. virtual ~EnumBodyParserTest(); void setUp(); void tearDown(); void testParseEmptyEnumBody(); void testParseOneConstant(); void testParseOneConstantWithValue(); void testParseOneConstantSkipTrailingComma(); void testParseTwoConstantWithSpaces(); void testParseThreeConstant(); void testParseThreeConstantWithValue(); void testParseTemplatedValue(); void testParseLeftShitOperatorValue(); private: void checkConstants( int constantCount ); void checkConstant( int index, const ASTNodePtr &constantNode ); void beginEnumBody(); void endEnumBody(); void addConstant( const std::string &name, bool addComma = true ); void addValue( const std::string &spacer, const std::string &value, bool addComma = true ); void addConstantValue( const std::string &name, const std::string &spacer, const std::string &value, bool addComma = true ); std::string makeKey( const std::string &prefix ); std::string source_; boost::shared_ptr<Testing::SourceBuilder> builder_; int constantNumber_; }; // Inlines methods for EnumBodyParserTest: // --------------------------------------- } // namespace Refactoring #endif // RFTA_ENUMBODYPARSERTEST_H |