Skip to content

Commit

Permalink
scripting: fix parser confusion when using constructor with equal nam…
Browse files Browse the repository at this point in the history
…e as service

I had to split out the constructor parsing from the data call parsing,
offering a similar functionality, but purely for type names.

Signed-off-by: Peter Soetens <[email protected]>
  • Loading branch information
Peter Soetens committed May 26, 2011
1 parent 799d3c2 commit 9b70629
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 42 deletions.
4 changes: 4 additions & 0 deletions rtt/scripting/CommonParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ namespace RTT {
BOOST_SPIRIT_DEBUG_RULE( notassertingidentifier );
BOOST_SPIRIT_DEBUG_RULE( lexeme_identifier );
BOOST_SPIRIT_DEBUG_RULE( lexeme_notassertingidentifier );
BOOST_SPIRIT_DEBUG_RULE( type_name );

// an identifier is a word which can be used to identify a
// label, or be the name of an object or method. it is required
Expand Down Expand Up @@ -140,6 +141,9 @@ namespace RTT {
eos = expect_eos( notassertingeos ); // detect } as eos, but do not consume.
notassertingeos = eol_p | ch_p(';') | eps_p(ch_p('}')); // detect } as eos, but do not consume.
leos = *(space_p - eol_p) >> (eol_p | ch_p(';') | eps_p(ch_p('}')));

chset<> t_identchar( "a-zA-Z-_0-9/<>." );
type_name = lexeme_d[ alpha_p >> *t_identchar ] - keyword;
}

void CommonParser::seenillegalidentifier()
Expand Down
2 changes: 1 addition & 1 deletion rtt/scripting/CommonParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace RTT { namespace scripting
rule_t notassertingidentifier; //! plain 'C' identifier. Does not throw if keyword is parsed.
lexeme_rule_t lexeme_identifier; //! See identifier, but in lexeme parsing mode.
lexeme_rule_t lexeme_notassertingidentifier; //! See notassertingidentifier, but in lexeme parsing mode.

rule_t type_name;
//@{
/**
* End Of Statement Parser. Identifies the end of a statement
Expand Down
120 changes: 83 additions & 37 deletions rtt/scripting/ExpressionParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ namespace RTT
method= ( commonparser.keyword | expect_ident(commonparser.tidentifier))[boost::bind( &DataCallParser::seenmethodname, this, _1, _2 ) ]; // may be send, call or method name.
datacall =
( peerpath >> !object >> method[ boost::bind( &DataCallParser::seendataname, this ) ] >> !arguments)[ boost::bind( &DataCallParser::seendatacall, this ) ];
};
}

void DataCallParser::seensend() {
mis_send = true;
Expand Down Expand Up @@ -134,12 +134,7 @@ namespace RTT
Service::shared_ptr ops = peerparser.taskObject();
peerparser.reset();
// cout << "seendataname "<< mobject << "." << mmethod<<endl;
// Check if it is a constructor
if ( (ops == peerparser.taskObject() && TypeInfoRepository::Instance()->type( mmethod ))
||
(TypeInfoRepository::Instance()->type( mobject + "." + mmethod )) ) {
// it is...
} else {
if (true) {
// it ain't...
// set the proper object name again in case of a send()
if (mis_send && ops)
Expand Down Expand Up @@ -197,17 +192,7 @@ namespace RTT
assert(peer && "peer may never be null.");
// cout << "seendatacall "<< mobject << "." << mmethod<<endl;

// separate track if we are handling a constructor:
if ( (obj == "this" && TypeInfoRepository::Instance()->type( meth )) ||
(TypeInfoRepository::Instance()->type( obj + "." + meth) ) ) {
if (obj == "this")
ret = TypeInfoRepository::Instance()->type( meth )->construct( args );
else
ret = TypeInfoRepository::Instance()->type( obj +"."+ meth )->construct( args );
if (!ret) {
throw parse_exception_no_such_constructor( meth, args );
}
} else {
if ( true ) {
// plain method or collect/collectIfDone

Service::shared_ptr ops = peer;
Expand Down Expand Up @@ -267,30 +252,81 @@ namespace RTT
delete argparsers.top();
argparsers.pop();
};
};
}

/** @cond */
static error_status<> handle_no_value(scanner_t const& scan, parser_error<std::string, iter_t>& e )
{
//std::cerr << "No value in EP : "<<e.descriptor<<std::endl;
// retry if it is a datacall, thus fail this rule
return error_status<>( error_status<>::fail );
}
ConstructorParser::ConstructorParser( ExpressionParser& p, CommonParser& cp)
: commonparser(cp), expressionparser( p )
{
BOOST_SPIRIT_DEBUG_RULE( type_name );
BOOST_SPIRIT_DEBUG_RULE( arguments );

type_name =
( commonparser.type_name[ boost::bind( &ConstructorParser::seen_type_name, this, _1, _2 ) ] >> !arguments)[ boost::bind( &ConstructorParser::seen_constructor, this ) ];
}

static error_status<> handle_no_datacall(scanner_t const& scan, parser_error<std::string, iter_t>&e )
ConstructorParser::~ConstructorParser()
{
// if argparsers is not empty, then something went wrong during
// the parsing ( someone threw an exception ), and we're
// responsible for cleaning up the argparsers we created..
while ( ! argparsers.empty() )
{
//retry with a member :
//std::cerr << "No DataCall in EP : "<<e.descriptor<<std::endl;
return error_status<>( error_status<>::fail );
delete argparsers.top();
argparsers.pop();
};
}


void ConstructorParser::seen_type_name( iter_t begin, iter_t end )
{
std::string name( begin, end );
TypeInfo* type = Types()->type( name );
if ( type == 0 )
throw_(iter_t(), "\"" + name + "\" is an unknown type...");

ArgumentsParser* argspar =
new ArgumentsParser( expressionparser, 0, Service::shared_ptr(), name, "" );

// keep hold of the argspar, we're still going to need it after
// it's done its work.. ( in seen_constructor(), that is.. )
argparsers.push( argspar );

// set the arguments parser to the parser provided by the
// ArgumentsParser we just created..
arguments = argspar->parser();

}

void ConstructorParser::seen_constructor( void )
{
ArgumentsParser* argspar = argparsers.top();
argparsers.pop();
std::string obj = argspar->objectname();
std::vector<DataSourceBase::shared_ptr> args = argspar->result();
delete argspar;

ret = TypeInfoRepository::Instance()->type( obj )->construct( args );

if (!ret) {
throw parse_exception_no_such_constructor( obj, args );
}

}

/** @cond */
static void abort_rule(const string& reason) {
throw_(iter_t(), reason);
}

static error_status<> fail_rule(scanner_t const& scan, parser_error<std::string, iter_t>&e )
{
return error_status<>( error_status<>::fail );
}
/** @endcond */

ExpressionParser::ExpressionParser( TaskContext* pc, ExecutionEngine* caller, CommonParser& cp )
: datacallparser( *this, cp, pc, caller ),
constrparser(*this, cp),
commonparser( cp ),
valueparser( pc, cp ),
_invert_time(false),
Expand Down Expand Up @@ -323,6 +359,7 @@ namespace RTT
BOOST_SPIRIT_DEBUG_RULE( close_brace );
BOOST_SPIRIT_DEBUG_RULE( value_expression );
BOOST_SPIRIT_DEBUG_RULE( call_expression );
BOOST_SPIRIT_DEBUG_RULE( constructor_expression );

comma = expect_comma( ch_p(',') );
close_brace = expect_close( ch_p(')') );
Expand Down Expand Up @@ -405,14 +442,17 @@ namespace RTT
| time_expression
// or a constant or user-defined value..
| value_expression
| constructor_expression
| call_expression
// or an index or dot expression
) >> *( dotexp | indexexp);

constructor_expression = my_guard( constrparser.parser()[ boost::bind(&ExpressionParser::seenconstructor, this)])[&fail_rule];

// if it's value.keyword then pass it on to the call_expression.
value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &handle_no_value ]
value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &fail_rule ]
[ bind( &ExpressionParser::seenvalue, this ) ];
call_expression = my_guard( datacallparser.parser() )[&handle_no_datacall]
call_expression = my_guard( datacallparser.parser() )[&fail_rule]
[bind( &ExpressionParser::seendatacall, this ) ];
// take index of an atomicexpression
indexexp =
Expand Down Expand Up @@ -515,6 +555,12 @@ namespace RTT
mhandle = datacallparser.getParseHandle();
}

void ExpressionParser::seenconstructor()
{
DataSourceBase::shared_ptr n( constrparser.getParseResult() );
parsestack.push( n );
}

ExpressionParser::~ExpressionParser()
{
// if parsestack is not empty, then something went wrong, someone
Expand Down Expand Up @@ -550,7 +596,7 @@ namespace RTT
throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op +
"\" to " + arg->getType() +"." );
parsestack.push( ret );
};
}

void ExpressionParser::seen_dotmember( iter_t s, iter_t f )
{
Expand All @@ -563,7 +609,7 @@ namespace RTT
throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member +
"\"." );
parsestack.push( ret );
};
}

void ExpressionParser::seen_binary( const std::string& op )
{
Expand All @@ -580,7 +626,7 @@ namespace RTT
throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op +
" "+arg1->getType() +"." );
parsestack.push( ret );
};
}

void ExpressionParser::seen_assign()
{
Expand Down Expand Up @@ -625,7 +671,7 @@ namespace RTT
ret = new DataSourceCommand( act ); // fall back into the old behavior of returning a boolean.
}
parsestack.push( ret );
};
}

void ExpressionParser::seen_index()
{
Expand All @@ -641,7 +687,7 @@ namespace RTT
throw parse_exception_fatal_semantic_error( "Illegal use of []: "+ arg2->getType() +"[ "
+arg1->getType() +" ]." );
parsestack.push( ret );
};
}

void ExpressionParser::dropResult()
{
Expand Down
39 changes: 35 additions & 4 deletions rtt/scripting/ExpressionParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,45 @@ namespace RTT { namespace scripting
rule_t& parser()
{
return datacall;
};
}

base::DataSourceBase* getParseResult()
{
return ret.get();
};
}
boost::shared_ptr<base::AttributeBase> getParseHandle()
{
return mhandle;
};
}
};

/**
* Parses type constructor syntax
*/
class ConstructorParser
{
base::DataSourceBase::shared_ptr ret;
rule_t type_name, arguments;

CommonParser& commonparser;
ExpressionParser& expressionparser;
std::stack<ArgumentsParser*> argparsers;
public:
ConstructorParser( ExpressionParser& p, CommonParser& cp);
~ConstructorParser();

void seen_type_name( iter_t begin, iter_t end );
void seen_constructor( void );

rule_t& parser()
{
return type_name;
}

base::DataSourceBase* getParseResult()
{
return ret.get();
}
};

/**
Expand All @@ -115,7 +144,7 @@ namespace RTT { namespace scripting
greatereqexp, greaterexp, equalexp, notequalexp, orexp, andexp,
ifthenelseexp, dotexp, groupexp, atomicexpression,
time_expression, time_spec, indexexp, comma, close_brace,
value_expression, call_expression, assignexp;
value_expression, call_expression, assignexp, constructor_expression;

/**
* The parse stack.. see the comment for this class ( scroll up
Expand Down Expand Up @@ -148,12 +177,14 @@ namespace RTT { namespace scripting
void seen_dotmember( iter_t begin, iter_t end );
void seenvalue();
void seendatacall();
void seenconstructor();
void seentimespec( int n );
void seentimeunit( iter_t begin, iter_t end );
void inverttime();
void seentimeexpr();

DataCallParser datacallparser;
ConstructorParser constrparser;
/**
* The governing common parser.
*/
Expand Down

0 comments on commit 9b70629

Please sign in to comment.