|
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
|