Parser now handles both namespace and class headers
parent
dbc6a8aeec
commit
ea1f1e8b65
|
@ -16,10 +16,9 @@
|
|||
|
||||
#include "Module.h"
|
||||
#include "utilities.h"
|
||||
#include "pop_actor.h"
|
||||
#include "spirit_actors.h"
|
||||
|
||||
//#define BOOST_SPIRIT_DEBUG
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/spirit/include/classic_confix.hpp>
|
||||
#include <boost/spirit/include/classic_clear_actor.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -53,7 +52,11 @@ Module::Module(const string& interfacePath,
|
|||
Method method0(enable_verbose), method(enable_verbose);
|
||||
StaticMethod static_method0(enable_verbose), static_method(enable_verbose);
|
||||
Class cls0(enable_verbose),cls(enable_verbose);
|
||||
vector<string> namespaces, namespaces_return;
|
||||
vector<string> namespaces, /// current namespace tag
|
||||
namespace_includes, /// current set of includes
|
||||
namespaces_return; /// namespace for current return type
|
||||
string include_path = "";
|
||||
const string null_str = "";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Grammar with actions that build the Class object. Actions are
|
||||
|
@ -169,20 +172,32 @@ Module::Module(const string& interfacePath,
|
|||
[push_back_a(cls.static_methods, static_method)]
|
||||
[assign_a(static_method,static_method0)];
|
||||
|
||||
Rule includes_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[push_back_a(cls.includes)] >> ch_p('>');
|
||||
|
||||
Rule functions_p = constructor_p | method_p | static_method_p;
|
||||
|
||||
Rule class_p = !includes_p >> (str_p("class") >> className_p[assign_a(cls.name)] >> '{' >>
|
||||
*(functions_p | comments_p) >>
|
||||
str_p("};"))[assign_a(cls.namespaces, namespaces)][push_back_a(classes,cls)][assign_a(cls,cls0)];
|
||||
Rule include_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[assign_a(include_path)] >> ch_p('>');
|
||||
|
||||
Rule namespace_def_p = str_p("namespace") >>
|
||||
namespace_name_p[push_back_a(namespaces)]
|
||||
>> ch_p('{') >>
|
||||
*(class_p | namespace_def_p | comments_p) >>
|
||||
str_p("}///\\namespace") >> !namespace_name_p // end namespace, avoid confusion with classes
|
||||
[pop_a(namespaces)];
|
||||
Rule class_p =
|
||||
(!include_p
|
||||
>> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)]
|
||||
>> className_p[assign_a(cls.name)]
|
||||
>> '{'
|
||||
>> *(functions_p | comments_p)
|
||||
>> str_p("};"))
|
||||
[assign_a(cls.namespaces, namespaces)]
|
||||
[append_a(cls.includes, namespace_includes)]
|
||||
[push_back_a(classes,cls)]
|
||||
[assign_a(cls,cls0)];
|
||||
|
||||
Rule namespace_def_p =
|
||||
(!include_p
|
||||
>> str_p("namespace")[push_back_a(namespace_includes, include_path)][assign_a(include_path, null_str)]
|
||||
>> namespace_name_p[push_back_a(namespaces)]
|
||||
>> ch_p('{')
|
||||
>> *(class_p | namespace_def_p | comments_p)
|
||||
>> str_p("}///\\namespace") // end namespace, avoid confusion with classes
|
||||
>> !namespace_name_p)
|
||||
[pop_a(namespaces)]
|
||||
[pop_a(namespace_includes)];
|
||||
|
||||
Rule using_namespace_p = str_p("using") >> str_p("namespace")
|
||||
>> namespace_name_p[push_back_a(using_namespaces)] >> ch_p(';');
|
||||
|
@ -210,6 +225,7 @@ Module::Module(const string& interfacePath,
|
|||
BOOST_SPIRIT_DEBUG_NODE(methodName_p);
|
||||
BOOST_SPIRIT_DEBUG_NODE(method_p);
|
||||
BOOST_SPIRIT_DEBUG_NODE(class_p);
|
||||
BOOST_SPIRIT_DEBUG_NODE(namespace_def_p);
|
||||
BOOST_SPIRIT_DEBUG_NODE(module_p);
|
||||
# endif
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
* @file pop_actor.h
|
||||
*
|
||||
* @brief An actor to pop a vector/container, based off of the clear_actor
|
||||
*
|
||||
* @date Dec 8, 2011
|
||||
* @author Alex Cunningham
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/spirit/include/classic_ref_actor.hpp>
|
||||
|
||||
namespace boost { namespace spirit {
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Summary:
|
||||
// A semantic action policy that calls pop_back method.
|
||||
// (This doc uses convention available in actors.hpp)
|
||||
//
|
||||
// Actions (what it does):
|
||||
// ref.pop_back();
|
||||
//
|
||||
// Policy name:
|
||||
// clear_action
|
||||
//
|
||||
// Policy holder, corresponding helper method:
|
||||
// ref_actor, clear_a( ref );
|
||||
//
|
||||
// () operators: both.
|
||||
//
|
||||
// See also ref_actor for more details.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
struct pop_action
|
||||
{
|
||||
template<
|
||||
typename T
|
||||
>
|
||||
void act(T& ref_) const
|
||||
{
|
||||
ref_.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// helper method that creates a and_assign_actor.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline ref_actor<T,pop_action> pop_a(T& ref_)
|
||||
{
|
||||
return ref_actor<T,pop_action>(ref_);
|
||||
}
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||
|
||||
}}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* @file spirit_actors.h
|
||||
*
|
||||
* @brief Additional actors for the wrap parser
|
||||
*
|
||||
* @date Dec 8, 2011
|
||||
* @author Alex Cunningham
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/spirit/include/classic_ref_actor.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace spirit {
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Summary:
|
||||
// A semantic action policy that calls pop_back method.
|
||||
// (This doc uses convention available in actors.hpp)
|
||||
// Note that this action performs a "safe" pop, that checks the size
|
||||
// before popping to avoid segfaults
|
||||
//
|
||||
// Actions (what it does):
|
||||
// ref.pop_back();
|
||||
//
|
||||
// Policy name:
|
||||
// pop_action
|
||||
//
|
||||
// Policy holder, corresponding helper method:
|
||||
// ref_actor, clear_a( ref );
|
||||
//
|
||||
// () operators: both.
|
||||
//
|
||||
// See also ref_actor for more details.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
struct pop_action
|
||||
{
|
||||
template< typename T>
|
||||
void act(T& ref_) const
|
||||
{
|
||||
if (!ref_.empty())
|
||||
ref_.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// helper method that creates a and_assign_actor.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline ref_actor<T,pop_action> pop_a(T& ref_)
|
||||
{
|
||||
return ref_actor<T,pop_action>(ref_);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Summary:
|
||||
//
|
||||
// A semantic action policy that appends a set of values to the back of a
|
||||
// container.
|
||||
// (This doc uses convention available in actors.hpp)
|
||||
//
|
||||
// Actions (what it does and what ref, value_ref must support):
|
||||
// ref.push_back( values );
|
||||
// ref.push_back( T::value_type(first,last) );
|
||||
// ref.push_back( value_ref );
|
||||
//
|
||||
// Policy name:
|
||||
// append_action
|
||||
//
|
||||
// Policy holder, corresponding helper method:
|
||||
// ref_value_actor, append_a( ref );
|
||||
// ref_const_ref_actor, append_a( ref, value_ref );
|
||||
//
|
||||
// () operators: both
|
||||
//
|
||||
// See also ref_value_actor and ref_const_ref_actor for more details.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct append_action
|
||||
{
|
||||
template< typename T, typename ValueT >
|
||||
void act(T& ref_, ValueT const& value_) const
|
||||
{
|
||||
ref_.insert(ref_.begin(), value_.begin(), value_.end());
|
||||
}
|
||||
|
||||
template<typename T,typename IteratorT>
|
||||
void act(
|
||||
T& ref_,
|
||||
IteratorT const& first_,
|
||||
IteratorT const& last_
|
||||
) const
|
||||
{
|
||||
ref_.insert(ref_.end(), first_, last_);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline ref_value_actor<T,append_action>
|
||||
append_a(T& ref_)
|
||||
{
|
||||
return ref_value_actor<T,append_action>(ref_);
|
||||
}
|
||||
|
||||
template<typename T,typename ValueT>
|
||||
inline ref_const_ref_actor<T,ValueT,append_action>
|
||||
append_a(
|
||||
T& ref_,
|
||||
ValueT const& value_
|
||||
)
|
||||
{
|
||||
return ref_const_ref_actor<T,ValueT,append_action>(ref_,value_);
|
||||
}
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2,20 +2,24 @@
|
|||
* This is a wrap header to verify permutations on namespaces
|
||||
*/
|
||||
|
||||
#include <path/to/ns1.h>
|
||||
namespace ns1 {
|
||||
|
||||
class ClassA {
|
||||
ClassA();
|
||||
};
|
||||
|
||||
#include <path/to/ns1/ClassB.h>
|
||||
class ClassB {
|
||||
ClassB();
|
||||
};
|
||||
|
||||
}///\namespace ns1
|
||||
|
||||
#include <path/to/ns2.h>
|
||||
namespace ns2 {
|
||||
|
||||
#include <path/to/ns2/ClassA.h>
|
||||
class ClassA {
|
||||
ClassA();
|
||||
static double afunction();
|
||||
|
@ -24,6 +28,7 @@ class ClassA {
|
|||
ns2::ns3::ClassB nsReturn(double q);
|
||||
};
|
||||
|
||||
#include <path/to/ns3.h>
|
||||
namespace ns3 {
|
||||
|
||||
class ClassB {
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <wrap/utilities.h>
|
||||
#include <wrap/Module.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
using namespace wrap;
|
||||
static bool enable_verbose = false;
|
||||
#ifdef TOPSRCDIR
|
||||
|
@ -33,6 +35,8 @@ static string topdir = TOPSRCDIR;
|
|||
static string topdir = "TOPSRCDIR_NOT_CONFIGURED"; // If TOPSRCDIR is not defined, we error
|
||||
#endif
|
||||
|
||||
typedef vector<string> strvec;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( wrap, ArgumentList ) {
|
||||
ArgumentList args;
|
||||
|
@ -117,8 +121,8 @@ TEST( wrap, parse ) {
|
|||
EXPECT_LONGS_EQUAL(19, testCls.methods.size());
|
||||
EXPECT_LONGS_EQUAL( 0, testCls.static_methods.size());
|
||||
EXPECT_LONGS_EQUAL( 0, testCls.namespaces.size());
|
||||
EXPECT_LONGS_EQUAL( 1, testCls.includes.size());
|
||||
EXPECT(assert_equal("folder/path/to/Test.h", testCls.includes.front()));
|
||||
strvec exp_includes; exp_includes += "folder/path/to/Test.h";
|
||||
EXPECT(assert_equal(exp_includes, testCls.includes));
|
||||
|
||||
// function to parse: pair<Vector,Matrix> return_pair (Vector v, Matrix A) const;
|
||||
Method m2 = testCls.methods.front();
|
||||
|
@ -134,35 +138,60 @@ TEST( wrap, parse_namespaces ) {
|
|||
Module module(header_path.c_str(), "testNamespaces",enable_verbose);
|
||||
EXPECT_LONGS_EQUAL(6, module.classes.size());
|
||||
|
||||
Class cls1 = module.classes.at(0);
|
||||
EXPECT(assert_equal("ClassA", cls1.name));
|
||||
EXPECT_LONGS_EQUAL(1, cls1.namespaces.size());
|
||||
EXPECT(assert_equal("ns1", cls1.namespaces.front()));
|
||||
{
|
||||
Class cls = module.classes.at(0);
|
||||
EXPECT(assert_equal("ClassA", cls.name));
|
||||
strvec exp_namespaces; exp_namespaces += "ns1";
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "path/to/ns1.h", "";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
Class cls2 = module.classes.at(1);
|
||||
EXPECT(assert_equal("ClassB", cls2.name));
|
||||
EXPECT_LONGS_EQUAL(1, cls2.namespaces.size());
|
||||
EXPECT(assert_equal("ns1", cls2.namespaces.front()));
|
||||
{
|
||||
Class cls = module.classes.at(1);
|
||||
EXPECT(assert_equal("ClassB", cls.name));
|
||||
strvec exp_namespaces; exp_namespaces += "ns1";
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "path/to/ns1.h", "path/to/ns1/ClassB.h";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
Class cls3 = module.classes.at(2);
|
||||
EXPECT(assert_equal("ClassA", cls3.name));
|
||||
EXPECT_LONGS_EQUAL(1, cls3.namespaces.size());
|
||||
EXPECT(assert_equal("ns2", cls3.namespaces.front()));
|
||||
{
|
||||
Class cls = module.classes.at(2);
|
||||
EXPECT(assert_equal("ClassA", cls.name));
|
||||
strvec exp_namespaces; exp_namespaces += "ns2";
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "path/to/ns2.h", "path/to/ns2/ClassA.h";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
Class cls4 = module.classes.at(3);
|
||||
EXPECT(assert_equal("ClassB", cls4.name));
|
||||
EXPECT_LONGS_EQUAL(2, cls4.namespaces.size());
|
||||
EXPECT(assert_equal("ns2", cls4.namespaces.front()));
|
||||
EXPECT(assert_equal("ns3", cls4.namespaces.back()));
|
||||
{
|
||||
Class cls = module.classes.at(3);
|
||||
EXPECT(assert_equal("ClassB", cls.name));
|
||||
strvec exp_namespaces; exp_namespaces += "ns2", "ns3";
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "path/to/ns2.h", "path/to/ns3.h", "";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
Class cls5 = module.classes.at(4);
|
||||
EXPECT(assert_equal("ClassC", cls5.name));
|
||||
EXPECT_LONGS_EQUAL(1, cls5.namespaces.size());
|
||||
EXPECT(assert_equal("ns2", cls5.namespaces.front()));
|
||||
{
|
||||
Class cls = module.classes.at(4);
|
||||
EXPECT(assert_equal("ClassC", cls.name));
|
||||
strvec exp_namespaces; exp_namespaces += "ns2";
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "path/to/ns2.h", "";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
{
|
||||
Class cls = module.classes.at(5);
|
||||
EXPECT(assert_equal("ClassD", cls.name));
|
||||
strvec exp_namespaces;
|
||||
EXPECT(assert_equal(exp_namespaces, cls.namespaces));
|
||||
strvec exp_includes; exp_includes += "";
|
||||
EXPECT(assert_equal(exp_includes, cls.includes));
|
||||
}
|
||||
|
||||
Class cls6 = module.classes.at(5);
|
||||
EXPECT(assert_equal("ClassD", cls6.name));
|
||||
EXPECT_LONGS_EQUAL(0, cls6.namespaces.size());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
|
@ -51,6 +51,34 @@ bool assert_equal(const string& expected, const string& actual) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool assert_equal(const vector<string>& expected, const vector<string>& actual) {
|
||||
bool match = true;
|
||||
if (expected.size() != actual.size())
|
||||
match = false;
|
||||
vector<string>::const_iterator
|
||||
itExp = expected.begin(),
|
||||
itAct = actual.begin();
|
||||
if(match) {
|
||||
for (; itExp!=expected.end() && itAct!=actual.end(); ++itExp, ++itAct) {
|
||||
if (*itExp != *itAct) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!match) {
|
||||
cout << "expected: " << endl;
|
||||
BOOST_FOREACH(const vector<string>::value_type& a, expected) { cout << "[" << a << "] "; }
|
||||
cout << "\nactual: " << endl;
|
||||
BOOST_FOREACH(const vector<string>::value_type& a, actual) { cout << "[" << a << "] "; }
|
||||
cout << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool files_equal(const string& expected, const string& actual, bool skipheader) {
|
||||
try {
|
||||
|
@ -97,8 +125,8 @@ void generateUsingNamespace(ofstream& ofs, const vector<string>& using_namespace
|
|||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void generateIncludes(std::ofstream& ofs, const std::string& class_name,
|
||||
const std::vector<std::string>& includes) {
|
||||
void generateIncludes(ofstream& ofs, const string& class_name,
|
||||
const vector<string>& includes) {
|
||||
ofs << "#include <wrap/matlab.h>" << endl;
|
||||
if (includes.empty()) // add a default include
|
||||
ofs << "#include <" << class_name << ".h>" << endl;
|
||||
|
|
|
@ -79,6 +79,7 @@ bool files_equal(const std::string& expected, const std::string& actual, bool sk
|
|||
* Compare strings for unit tests
|
||||
*/
|
||||
bool assert_equal(const std::string& expected, const std::string& actual);
|
||||
bool assert_equal(const std::vector<std::string>& expected, const std::vector<std::string>& actual);
|
||||
/**
|
||||
* emit a header at the top of generated files
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue