support global functions (no overload)

release/4.3a0
Duy-Nguyen Ta 2016-11-22 17:09:35 -05:00
parent 74f80fea4f
commit 338c73669e
10 changed files with 124 additions and 53 deletions

View File

@ -0,0 +1,35 @@
#include "FullyOverloadedFunction.h"
using namespace std;
namespace wrap {
const std::array<std::string, 2> FullyOverloadedFunction::pythonKeywords{
{"print", "lambda"}};
/* ************************************************************************* */
std::string FullyOverloadedFunction::pyx_functionCall(
const std::string& caller,
const std::string& funcName, size_t iOverload) const {
string ret;
if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr &&
returnVals_[iOverload].type1.isNonBasicType()) {
ret = returnVals_[iOverload].type1.shared_pxd_class_in_pyx() + "(new " +
returnVals_[iOverload].type1.pxd_class_in_pyx() + "(";
}
// actual function call ...
if (!caller.empty()) ret += caller + ".";
ret += funcName;
if (templateArgValue_) ret += "[" + templateArgValue_->pxd_class_in_pyx() + "]";
//... with argument list
ret += "(" + argumentList(iOverload).pyx_asParams() + ")";
if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr &&
returnVals_[iOverload].type1.isNonBasicType())
ret += "))";
return ret;
}
}

View File

@ -19,6 +19,7 @@
#pragma once
#include "OverloadedFunction.h"
#include <array>
namespace wrap {
@ -116,6 +117,19 @@ public:
return first;
}
// emit cython pyx function call
std::string pyx_functionCall(const std::string& caller, const std::string& funcName,
size_t iOverload) const;
/// Cython: Rename functions which names are python keywords
static const std::array<std::string, 2> pythonKeywords;
static std::string pyRename(const std::string& name) {
if (std::find(pythonKeywords.begin(), pythonKeywords.end(), name) ==
pythonKeywords.end())
return name;
else
return name + "_";
}
};
// Templated checking functions

View File

@ -16,11 +16,12 @@ using namespace std;
/* ************************************************************************* */
void GlobalFunction::addOverload(const Qualified& overload,
const ArgumentList& args, const ReturnValue& retVal,
const ArgumentList& args, const ReturnValue& retVal, const std::string& _includeFile,
boost::optional<const Qualified> instName, bool verbose) {
FullyOverloadedFunction::addOverload(overload.name(), args, retVal, instName,
verbose);
overloads.push_back(overload);
includeFile = _includeFile;
}
/* ************************************************************************* */
@ -131,6 +132,47 @@ void GlobalFunction::python_wrapper(FileWriter& wrapperFile) const {
wrapperFile.oss << "def(\"" << name_ << "\", " << name_ << ");\n";
}
/* ************************************************************************* */
void GlobalFunction::emit_cython_pxd(FileWriter& file) const {
file.oss << "cdef extern from \"" << includeFile << "\" namespace \""
<< overloads[0].qualifiedNamespaces("::")
<< "\":" << endl;
for (size_t i = 0; i < nrOverloads(); ++i) {
file.oss << "\t\t";
returnVals_[i].emit_cython_pxd(file, "");
file.oss << pyRename(name_) + " \"" + overloads[0].qualifiedName("::") +
"\"(";
argumentList(i).emit_cython_pxd(file, "");
file.oss << ")";
file.oss << "\n";
}
}
/* ************************************************************************* */
void GlobalFunction::emit_cython_pyx(FileWriter& file) const {
string funcName = pyRename(name_);
// Function definition
file.oss << "def " << funcName;
// modify name of function instantiation as python doesn't allow overloads
// e.g. template<T={A,B,C}> funcName(...) --> funcNameA, funcNameB, funcNameC
if (templateArgValue_) file.oss << templateArgValue_->name();
// funtion arguments
file.oss << "(";
argumentList(0).emit_cython_pyx(file);
file.oss << "):\n";
/// Call cython corresponding function and return
string ret = pyx_functionCall("pxd", funcName, 0);
if (!returnVals_[0].isVoid()) {
file.oss << "\tcdef " << returnVals_[0].pyx_returnType()
<< " ret = " << ret << "\n";
file.oss << "\treturn " << returnVals_[0].pyx_casting("ret") << "\n";
} else {
file.oss << "\t" << ret << "\n";
}
}
/* ************************************************************************* */
} // \namespace wrap

View File

@ -28,10 +28,11 @@ namespace wrap {
struct GlobalFunction: public FullyOverloadedFunction {
std::vector<Qualified> overloads; ///< Stack of qualified names
std::string includeFile;
// adds an overloaded version of this function,
void addOverload(const Qualified& overload, const ArgumentList& args,
const ReturnValue& retVal, boost::optional<const Qualified> instName =
const ReturnValue& retVal, const std::string& _includeFile = "", boost::optional<const Qualified> instName =
boost::none, bool verbose = false);
void verifyArguments(const std::vector<std::string>& validArgs) const {
@ -50,6 +51,10 @@ struct GlobalFunction: public FullyOverloadedFunction {
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile) const;
// emit cython wrapper
void emit_cython_pxd(FileWriter& pxdFile) const;
void emit_cython_pyx(FileWriter& pyxFile) const;
private:
// Creates a single global function - all in same namespace
@ -67,12 +72,15 @@ struct GlobalFunctionGrammar: public classic::grammar<GlobalFunctionGrammar> {
GlobalFunctions& global_functions_; ///< successful parse will be placed in here
std::vector<std::string>& namespaces_;
std::string& includeFile;
/// Construct type grammar and specify where result is placed
GlobalFunctionGrammar(GlobalFunctions& global_functions,
std::vector<std::string>& namespaces) :
global_functions_(global_functions), namespaces_(namespaces) {
}
std::vector<std::string>& namespaces,
std::string& includeFile)
: global_functions_(global_functions),
namespaces_(namespaces),
includeFile(includeFile) {}
/// Definition of type grammar
template<typename ScannerT>
@ -101,16 +109,16 @@ struct GlobalFunctionGrammar: public classic::grammar<GlobalFunctionGrammar> {
globalFunctionName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')];
// parse a global function
global_function_p = (returnValue_g
>> globalFunctionName_p[assign_a(globalFunction.name_)]
>> argumentList_g >> ';' >> *comments_p) //
[assign_a(globalFunction.namespaces_, self.namespaces_)][bl::bind(
global_function_p = (returnValue_g >> globalFunctionName_p[assign_a(
globalFunction.name_)] >>
argumentList_g >> ';' >> *comments_p) //
[assign_a(globalFunction.namespaces_, self.namespaces_)] //
[bl::bind(
&GlobalFunction::addOverload,
bl::var(self.global_functions_)[bl::var(globalFunction.name_)],
bl::var(globalFunction), bl::var(args), bl::var(retVal),
boost::none, verbose)] //
bl::var(globalFunction), bl::var(args), bl::var(retVal), bl::var(self.includeFile),
boost::none, verbose)] //
[assign_a(retVal, retVal0)][clear_a(globalFunction)][clear_a(args)];
}
classic::rule<ScannerT> const& start() const {

View File

@ -28,17 +28,6 @@
using namespace std;
using namespace wrap;
/* ************************************************************************* */
/// Cython: Rename functions which names are python keywords
static const std::array<std::string, 2> pythonKeywords{{"print", "lambda"}};
static std::string pyRename(const std::string& name) {
if (std::find(pythonKeywords.begin(), pythonKeywords.end(), name) ==
pythonKeywords.end())
return name;
else
return name + "_";
}
/* ************************************************************************* */
bool Method::addOverload(Str name, const ArgumentList& args,
const ReturnValue& retVal, bool is_const,

View File

@ -138,28 +138,3 @@ void MethodBase::python_wrapper(FileWriter& wrapperFile, Str className) const {
}
/* ************************************************************************* */
std::string MethodBase::pyx_functionCall(
const std::string& caller,
const std::string& funcName, size_t iOverload) const {
string ret;
if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr &&
returnVals_[iOverload].type1.isNonBasicType()) {
ret = returnVals_[iOverload].type1.shared_pxd_class_in_pyx() + "(new " +
returnVals_[iOverload].type1.pxd_class_in_pyx() + "(";
}
// actual function call ...
ret += caller + "." + funcName;
if (templateArgValue_) ret += "[" + templateArgValue_->pxd_class_in_pyx() + "]";
//... with argument list
ret += "(" + argumentList(iOverload).pyx_asParams() + ")";
if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr &&
returnVals_[iOverload].type1.isNonBasicType())
ret += "))";
return ret;
}
/* ************************************************************************* */

View File

@ -54,10 +54,6 @@ struct MethodBase : public FullyOverloadedFunction {
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile, Str className) const;
// emit cython pyx function call
std::string pyx_functionCall(const std::string& caller, const std::string& funcName,
size_t iOverload) const;
protected:
virtual void proxy_header(FileWriter& proxyFile) const = 0;

View File

@ -149,7 +149,8 @@ void Module::parseMarkup(const std::string& data) {
bl::var(newType), bl::var(currentInclude))];
// Create grammar for global functions
GlobalFunctionGrammar global_function_g(global_functions,namespaces);
GlobalFunctionGrammar global_function_g(global_functions, namespaces,
currentInclude);
Rule include_p = str_p("#include") >> ch_p('<') >>
(*(anychar_p - '>'))[push_back_a(includes)]
@ -364,6 +365,11 @@ void Module::emit_cython_pxd(FileWriter& pxdFile) const {
}
pxdFile.oss << "\n\n";
}
//... wrap global functions
for(const GlobalFunctions::value_type& p: global_functions)
p.second.emit_cython_pxd(pxdFile);
pxdFile.emit(true);
}
@ -387,6 +393,9 @@ void Module::emit_cython_pyx(FileWriter& pyxFile) const {
for(const Class& cls: expandedClasses)
cls.emit_cython_pyx(pyxFile, expandedClasses);
pyxFile.oss << "\n";
//... wrap global functions
for(const GlobalFunctions::value_type& p: global_functions)
p.second.emit_cython_pyx(pyxFile);
pyxFile.emit(true);
}

View File

@ -43,7 +43,9 @@ struct ReturnType : public Qualified {
throw DependencyMissing(key, "checking return type of " + s);
}
/// @param className the actual class name to use when "This" is specified
void emit_cython_pxd(FileWriter& file, const std::string& className) const;
std::string pyx_returnType(bool addShared = true) const;
std::string pyx_casting(const std::string& var,
bool isSharedVar = true) const;

View File

@ -71,6 +71,7 @@ struct ReturnValue {
void emit_matlab(FileWriter& proxyFile) const;
/// @param className the actual class name to use when "This" is specified
void emit_cython_pxd(FileWriter& file, const std::string& className) const;
std::string pyx_returnType() const;
std::string pyx_casting(const std::string& var) const;