gtsam/wrap/Argument.h

243 lines
7.1 KiB
C
Raw Normal View History

/* ----------------------------------------------------------------------------
2019-02-11 22:39:48 +08:00
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file Argument.h
* @brief arguments to constructors and methods
* @author Frank Dellaert
2012-06-27 02:52:27 +08:00
* @author Andrew Melim
2012-07-13 06:28:28 +08:00
* @author Richard Roberts
**/
#pragma once
#include "TemplateSubstitution.h"
2014-05-26 01:29:06 +08:00
#include "FileWriter.h"
#include "ReturnValue.h"
2014-05-26 01:29:06 +08:00
namespace wrap {
2011-10-14 12:43:06 +08:00
/// Argument class
struct Argument {
Qualified type;
std::string name;
2014-11-30 23:08:42 +08:00
bool is_const, is_ref, is_ptr;
Argument() :
is_const(false), is_ref(false), is_ptr(false) {
}
2011-10-14 12:43:06 +08:00
2014-11-30 23:08:42 +08:00
Argument(const Qualified& t, const std::string& n) :
type(t), name(n), is_const(false), is_ref(false), is_ptr(false) {
}
bool isSameSignature(const Argument& other) const {
return type == other.type
&& is_const == other.is_const && is_ref == other.is_ref
&& is_ptr == other.is_ptr;
}
2014-11-30 23:08:42 +08:00
bool operator==(const Argument& other) const {
return type == other.type && name == other.name
&& is_const == other.is_const && is_ref == other.is_ref
&& is_ptr == other.is_ptr;
}
Argument expandTemplate(const TemplateSubstitution& ts) const;
/// return MATLAB class for use in isa(x,class)
std::string matlabClass(const std::string& delim = "") const;
/// MATLAB code generation, MATLAB to C++
void matlab_unwrap(FileWriter& file, const std::string& matlabName) const;
2014-11-14 04:11:29 +08:00
2014-11-30 04:11:13 +08:00
/**
* emit checking argument to MATLAB proxy
* @param proxyFile output stream
*/
2014-11-30 04:43:48 +08:00
void proxy_check(FileWriter& proxyFile, const std::string& s) const;
2014-11-30 04:11:13 +08:00
2016-09-09 01:33:32 +08:00
/**
* emit arguments for cython pxd
* @param file output stream
*/
void emit_cython_pxd(FileWriter& file, const std::string& className,
const std::vector<std::string>& templateArgs) const;
void emit_cython_pyx(FileWriter& file) const;
std::string pyx_asParam() const;
convert numpy input params to dtype float and order 'F' automatically using numpy.astype(...). No copy if the params are already in the correct dtype and storage order. For a function f(Matrix A, Matrix B), simply wrapping it to pyx as f(A.astype(float, order='F', copy=False), B.astype(float, order='F', copy=False)) won't work. It produces a strange side-effect that the content of A is overwritten by B and the two inputs are the same (data address) inside the function! This is because Cython decreases the ref count for the temporary variable resulted from A.astype(...) before generates the wrap for B.astype(...). Hence, the A.astype temp var is probably reused for B.astype, and they were pointing to the same data address. For that reason, we have to go a longer route and wrap it as: A = A.astype(float, order='F', copy=False) B = B.astype(float, order='F', copy=False) f(A, B) For future ref., here is a sample of the wrongly generated code that wraps the JacobianFactor constructor: Jacobian(Key i1, Matrix A1, Key i2, Matrix A2, Vector b, noiseModel::Diagonal model) Wrongly wrapped pyx code: self.shared_CJacobianFactor_ = shared_ptr[CJacobianFactor](new CJacobianFactor(i1, <MatrixXd>(Map[MatrixXd](A1.astype(float, order='F',copy=False)), i2, <MatrixXd>(Map[MatrixXd](A2.astype(float, order='F', copy=False)), <VectorXd>(Map[VectorXd](b.astype(float, order='F', copy=False))), model.shared_CnoiseModel_Diagonal_)) The problematic Cython generated CPP code with a comment on the problematic line: ///////////////////////////////////////// // WRONG VERSION ///////////////////////////////////////// __pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A1), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_14 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_13)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } /////////////////////////////////////////////// __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; //<------- Problematic line!!! Killing this will result in the correct result! /////////////////////////////////////////////// __pyx_t_13 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A2), __pyx_n_s_astype); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_4 = PyDict_New(); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if (!(likely(((__pyx_t_12) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_12, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_15 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_12)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_b), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_16 = eigency::Map<Eigen::VectorXd> (((PyArrayObject *)__pyx_t_13)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; try { __pyx_t_17 = new gtsam::JacobianFactor(__pyx_v_i1, ((Eigen::MatrixXd)__pyx_t_14), __pyx_v_i2, ((Eigen::MatrixXd)__pyx_t_15), ((Eigen::VectorXd)__pyx_t_16), __pyx_v_model->shared_CnoiseModel_Diagonal_); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __pyx_v_self->shared_CJacobianFactor_ = boost::shared_ptr<gtsam::JacobianFactor> (__pyx_t_17);
2017-03-16 01:47:11 +08:00
std::string pyx_convertEigenTypeAndStorageOrder() const;
2016-09-09 01:33:32 +08:00
2014-11-14 04:11:29 +08:00
friend std::ostream& operator<<(std::ostream& os, const Argument& arg) {
os << (arg.is_const ? "const " : "") << arg.type << (arg.is_ptr ? "*" : "")
<< (arg.is_ref ? "&" : "");
return os;
}
};
/// Argument list is just a container with Arguments
2011-12-09 04:51:15 +08:00
struct ArgumentList: public std::vector<Argument> {
/// create a comma-separated string listing all argument types (not used)
std::string types() const;
/// create a short "signature" string
std::string signature() const;
/// create a comma-separated string listing all argument names, used in m-files
std::string names() const;
2011-10-14 12:43:06 +08:00
/// Check if all arguments scalar
bool allScalar() const;
ArgumentList expandTemplate(const TemplateSubstitution& ts) const;
bool isSameSignature(const ArgumentList& other) const {
2019-02-11 22:39:48 +08:00
for(size_t i = 0; i<size(); ++i)
if (!at(i).isSameSignature(other[i])) return false;
return true;
}
// MATLAB code generation:
2011-10-14 12:43:06 +08:00
/**
* emit code to unwrap arguments
* @param file output stream
* @param start initial index for input array, set to 1 for method
*/
void matlab_unwrap(FileWriter& file, int start = 0) const; // MATLAB to C++
2012-06-27 02:52:27 +08:00
/**
* emit MATLAB prototype
* @param file output stream
* @param name of method or function
*/
void emit_prototype(FileWriter& file, const std::string& name) const;
2016-09-09 01:33:32 +08:00
/**
* emit arguments for cython pxd
* @param file output stream
*/
void emit_cython_pxd(FileWriter& file, const std::string& className,
const std::vector<std::string>& templateArgs) const;
void emit_cython_pyx(FileWriter& file) const;
std::string pyx_asParams() const;
std::string pyx_paramsList() const;
std::string pyx_castParamsToPythonType(const std::string& indent) const;
convert numpy input params to dtype float and order 'F' automatically using numpy.astype(...). No copy if the params are already in the correct dtype and storage order. For a function f(Matrix A, Matrix B), simply wrapping it to pyx as f(A.astype(float, order='F', copy=False), B.astype(float, order='F', copy=False)) won't work. It produces a strange side-effect that the content of A is overwritten by B and the two inputs are the same (data address) inside the function! This is because Cython decreases the ref count for the temporary variable resulted from A.astype(...) before generates the wrap for B.astype(...). Hence, the A.astype temp var is probably reused for B.astype, and they were pointing to the same data address. For that reason, we have to go a longer route and wrap it as: A = A.astype(float, order='F', copy=False) B = B.astype(float, order='F', copy=False) f(A, B) For future ref., here is a sample of the wrongly generated code that wraps the JacobianFactor constructor: Jacobian(Key i1, Matrix A1, Key i2, Matrix A2, Vector b, noiseModel::Diagonal model) Wrongly wrapped pyx code: self.shared_CJacobianFactor_ = shared_ptr[CJacobianFactor](new CJacobianFactor(i1, <MatrixXd>(Map[MatrixXd](A1.astype(float, order='F',copy=False)), i2, <MatrixXd>(Map[MatrixXd](A2.astype(float, order='F', copy=False)), <VectorXd>(Map[VectorXd](b.astype(float, order='F', copy=False))), model.shared_CnoiseModel_Diagonal_)) The problematic Cython generated CPP code with a comment on the problematic line: ///////////////////////////////////////// // WRONG VERSION ///////////////////////////////////////// __pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A1), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_14 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_13)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } /////////////////////////////////////////////// __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; //<------- Problematic line!!! Killing this will result in the correct result! /////////////////////////////////////////////// __pyx_t_13 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A2), __pyx_n_s_astype); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_4 = PyDict_New(); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if (!(likely(((__pyx_t_12) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_12, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_15 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_12)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_b), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_12); __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_INCREF(((PyObject *)(&PyFloat_Type))); __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type))); PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type))); __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error) __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_13); __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error) try { __pyx_t_16 = eigency::Map<Eigen::VectorXd> (((PyArrayObject *)__pyx_t_13)); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; try { __pyx_t_17 = new gtsam::JacobianFactor(__pyx_v_i1, ((Eigen::MatrixXd)__pyx_t_14), __pyx_v_i2, ((Eigen::MatrixXd)__pyx_t_15), ((Eigen::VectorXd)__pyx_t_16), __pyx_v_model->shared_CnoiseModel_Diagonal_); } catch(...) { __Pyx_CppExn2PyErr(); __PYX_ERR(0, 2107, __pyx_L1_error) } __pyx_v_self->shared_CJacobianFactor_ = boost::shared_ptr<gtsam::JacobianFactor> (__pyx_t_17);
2017-03-16 01:47:11 +08:00
std::string pyx_convertEigenTypeAndStorageOrder(const std::string& indent) const;
2016-09-09 01:33:32 +08:00
/**
2014-11-30 03:53:38 +08:00
* emit checking arguments to MATLAB proxy
* @param proxyFile output stream
2014-05-26 02:59:20 +08:00
*/
2014-11-30 04:11:13 +08:00
void proxy_check(FileWriter& proxyFile) const;
2014-11-14 04:11:29 +08:00
2014-11-30 03:53:38 +08:00
/// Output stream operator
2014-11-14 04:11:29 +08:00
friend std::ostream& operator<<(std::ostream& os,
const ArgumentList& argList) {
os << "(";
if (argList.size() > 0)
os << argList.front();
if (argList.size() > 1)
for (size_t i = 1; i < argList.size(); i++)
os << ", " << argList[i];
os << ")";
return os;
}
};
2014-12-01 03:25:26 +08:00
/* ************************************************************************* */
// http://boost-spirit.com/distrib/spirit_1_8_2/libs/spirit/doc/grammar.html
struct ArgumentGrammar: public classic::grammar<ArgumentGrammar> {
wrap::Argument& result_; ///< successful parse will be placed in here
2014-12-02 03:03:26 +08:00
TypeGrammar argument_type_g; ///< Type parser for Argument::type
2014-12-01 03:25:26 +08:00
/// Construct type grammar and specify where result is placed
ArgumentGrammar(wrap::Argument& result) :
result_(result), argument_type_g(result.type) {
}
/// Definition of type grammar
template<typename ScannerT>
2014-12-02 03:03:26 +08:00
struct definition: BasicRules<ScannerT> {
2014-12-01 03:25:26 +08:00
typedef classic::rule<ScannerT> Rule;
2014-12-02 03:03:26 +08:00
Rule argument_p;
2014-12-01 03:25:26 +08:00
definition(ArgumentGrammar const& self) {
using namespace classic;
// NOTE: allows for pointers to all types
// Slightly more permissive than before on basis/eigen type qualification
// Also, currently parses Point2*&, can't make it work otherwise :-(
argument_p = !str_p("const")[assign_a(self.result_.is_const, T)] //
>> self.argument_type_g //
>> !ch_p('*')[assign_a(self.result_.is_ptr, T)]
>> !ch_p('&')[assign_a(self.result_.is_ref, T)]
2014-12-02 03:03:26 +08:00
>> BasicRules<ScannerT>::name_p[assign_a(self.result_.name)];
2014-12-01 03:25:26 +08:00
}
Rule const& start() const {
return argument_p;
}
};
};
// ArgumentGrammar
/* ************************************************************************* */
// http://boost-spirit.com/distrib/spirit_1_8_2/libs/spirit/doc/grammar.html
struct ArgumentListGrammar: public classic::grammar<ArgumentListGrammar> {
wrap::ArgumentList& result_; ///< successful parse will be placed in here
/// Construct type grammar and specify where result is placed
ArgumentListGrammar(wrap::ArgumentList& result) :
result_(result) {
2014-12-01 03:25:26 +08:00
}
/// Definition of type grammar
template<typename ScannerT>
2014-12-02 03:03:26 +08:00
struct definition {
2014-12-01 03:25:26 +08:00
const Argument arg0; ///< used to reset arg
Argument arg; ///< temporary argument for use during parsing
ArgumentGrammar argument_g; ///< single Argument parser
2014-12-02 03:03:26 +08:00
classic::rule<ScannerT> argument_p, argumentList_p;
2014-12-01 03:25:26 +08:00
definition(ArgumentListGrammar const& self) :
argument_g(arg) {
2014-12-01 03:25:26 +08:00
using namespace classic;
2014-12-02 03:03:26 +08:00
argument_p = argument_g //
[classic::push_back_a(self.result_, arg)] //
[assign_a(arg, arg0)];
2014-12-02 03:03:26 +08:00
2014-12-01 03:25:26 +08:00
argumentList_p = '(' >> !argument_p >> *(',' >> argument_p) >> ')';
}
2014-12-02 03:03:26 +08:00
classic::rule<ScannerT> const& start() const {
2014-12-01 03:25:26 +08:00
return argumentList_p;
}
};
};
// ArgumentListGrammar
/* ************************************************************************* */
}// \namespace wrap