mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge pull request #12269 from cv3d:improvements/binding_python
This commit is contained in:
@@ -307,6 +307,9 @@ Cv64suf;
|
||||
#define CV_PROP_RW
|
||||
#define CV_WRAP
|
||||
#define CV_WRAP_AS(synonym)
|
||||
#define CV_WRAP_MAPPABLE(mappable)
|
||||
#define CV_WRAP_PHANTOM(phantom_header)
|
||||
#define CV_WRAP_DEFAULT(val)
|
||||
|
||||
/****************************************************************************************\
|
||||
* Matrix type (Mat) *
|
||||
|
||||
@@ -341,6 +341,7 @@ class JavaWrapperGenerator(object):
|
||||
self.classes = { "Mat" : ClassInfo([ 'class Mat', '', [], [] ], self.namespaces) }
|
||||
self.module = ""
|
||||
self.Module = ""
|
||||
self.enum_types = []
|
||||
self.ported_func_list = []
|
||||
self.skipped_func_list = []
|
||||
self.def_args_hist = {} # { def_args_cnt : funcs_cnt }
|
||||
@@ -421,6 +422,10 @@ class JavaWrapperGenerator(object):
|
||||
ci.addConst(constinfo)
|
||||
logging.info('ok: %s', constinfo)
|
||||
|
||||
def add_enum(self, decl): # [ "enum cname", "", [], [] ]
|
||||
enumname = decl[0].replace("enum ", "").strip()
|
||||
self.enum_types.append(enumname)
|
||||
|
||||
def add_func(self, decl):
|
||||
fi = FuncInfo(decl, namespaces=self.namespaces)
|
||||
classname = fi.classname or self.Module
|
||||
@@ -479,6 +484,9 @@ class JavaWrapperGenerator(object):
|
||||
self.add_class(decl)
|
||||
elif name.startswith("const"):
|
||||
self.add_const(decl)
|
||||
elif name.startswith("enum"):
|
||||
# enum
|
||||
self.add_enum(decl)
|
||||
else: # function
|
||||
self.add_func(decl)
|
||||
|
||||
|
||||
+134
-3
@@ -27,6 +27,80 @@
|
||||
# define CV_PYTHON_TYPE_HEAD_INIT() PyObject_HEAD_INIT(&PyType_Type) 0,
|
||||
#endif
|
||||
|
||||
#define CV_PY_TO_CLASS(TYPE) \
|
||||
template<> bool pyopencv_to(PyObject* dst, Ptr<TYPE>& src, const char* name); \
|
||||
\
|
||||
template<> \
|
||||
bool pyopencv_to(PyObject* dst, TYPE& src, const char* name) \
|
||||
{ \
|
||||
if (!dst || dst == Py_None) \
|
||||
return true; \
|
||||
Ptr<TYPE> ptr; \
|
||||
\
|
||||
if (!pyopencv_to(dst, ptr, name)) return false; \
|
||||
src = *ptr; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define CV_PY_FROM_CLASS(TYPE) \
|
||||
template<> PyObject* pyopencv_from(const Ptr<TYPE>& src); \
|
||||
\
|
||||
template<> \
|
||||
PyObject* pyopencv_from(const TYPE& src) \
|
||||
{ \
|
||||
Ptr<TYPE> ptr(new TYPE()); \
|
||||
\
|
||||
*ptr = src; \
|
||||
return pyopencv_from(ptr); \
|
||||
}
|
||||
|
||||
#define CV_PY_TO_CLASS_PTR(TYPE) \
|
||||
template<> bool pyopencv_to(PyObject* dst, Ptr<TYPE>& src, const char* name); \
|
||||
\
|
||||
template<> \
|
||||
bool pyopencv_to(PyObject* dst, TYPE*& src, const char* name) \
|
||||
{ \
|
||||
if (!dst || dst == Py_None) \
|
||||
return true; \
|
||||
Ptr<TYPE> ptr; \
|
||||
\
|
||||
if (!pyopencv_to(dst, ptr, name)) return false; \
|
||||
src = ptr; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define CV_PY_FROM_CLASS_PTR(TYPE) \
|
||||
template<> PyObject* pyopencv_from(const Ptr<TYPE>& src); \
|
||||
\
|
||||
static PyObject* pyopencv_from(TYPE*& src) \
|
||||
{ \
|
||||
return pyopencv_from(Ptr<TYPE>(src)); \
|
||||
}
|
||||
|
||||
#define CV_PY_TO_ENUM(TYPE) \
|
||||
template<> bool pyopencv_to(PyObject* dst, std::underlying_type<TYPE>::type& src, const char* name); \
|
||||
\
|
||||
template<> \
|
||||
bool pyopencv_to(PyObject* dst, TYPE& src, const char* name) \
|
||||
{ \
|
||||
if (!dst || dst == Py_None) \
|
||||
return true; \
|
||||
std::underlying_type<TYPE>::type underlying; \
|
||||
\
|
||||
if (!pyopencv_to(dst, underlying, name)) return false; \
|
||||
src = static_cast<TYPE>(underlying); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define CV_PY_FROM_ENUM(TYPE) \
|
||||
template<> PyObject* pyopencv_from(const std::underlying_type<TYPE>::type& src); \
|
||||
\
|
||||
template<> \
|
||||
PyObject* pyopencv_from(const TYPE& src) \
|
||||
{ \
|
||||
return pyopencv_from(static_cast<std::underlying_type<TYPE>::type>(src)); \
|
||||
}
|
||||
|
||||
#include "pyopencv_generated_include.h"
|
||||
#include "opencv2/core/types_c.h"
|
||||
|
||||
@@ -36,7 +110,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
static PyObject* opencv_error = 0;
|
||||
static PyObject* opencv_error = NULL;
|
||||
|
||||
static int failmsg(const char *fmt, ...)
|
||||
{
|
||||
@@ -97,6 +171,12 @@ try \
|
||||
} \
|
||||
catch (const cv::Exception &e) \
|
||||
{ \
|
||||
PyObject_SetAttrString(opencv_error, "file", PyString_FromString(e.file.c_str())); \
|
||||
PyObject_SetAttrString(opencv_error, "func", PyString_FromString(e.func.c_str())); \
|
||||
PyObject_SetAttrString(opencv_error, "line", PyInt_FromLong(e.line)); \
|
||||
PyObject_SetAttrString(opencv_error, "code", PyInt_FromLong(e.code)); \
|
||||
PyObject_SetAttrString(opencv_error, "msg", PyString_FromString(e.msg.c_str())); \
|
||||
PyObject_SetAttrString(opencv_error, "err", PyString_FromString(e.err.c_str())); \
|
||||
PyErr_SetString(opencv_error, e.what()); \
|
||||
return 0; \
|
||||
}
|
||||
@@ -735,12 +815,31 @@ bool pyopencv_to(PyObject* o, UMat& um, const char* name)
|
||||
}
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const UMat& m) {
|
||||
PyObject* pyopencv_from(const UMat& m)
|
||||
{
|
||||
PyObject *o = PyObject_CallObject((PyObject *) &cv2_UMatWrapperType, NULL);
|
||||
*((cv2_UMatWrapperObject *) o)->um = m;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, void*& ptr, const char* name)
|
||||
{
|
||||
(void)name;
|
||||
if (!obj || obj == Py_None)
|
||||
return true;
|
||||
|
||||
if (!PyLong_Check(obj))
|
||||
return false;
|
||||
ptr = PyLong_AsVoidPtr(obj);
|
||||
return ptr != NULL && !PyErr_Occurred();
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_from(void*& ptr)
|
||||
{
|
||||
return PyLong_FromVoidPtr(ptr);
|
||||
}
|
||||
|
||||
static bool pyopencv_to(PyObject *o, Scalar& s, const ArgInfo info)
|
||||
{
|
||||
if(!o || o == Py_None)
|
||||
@@ -843,6 +942,30 @@ bool pyopencv_to(PyObject* obj, int& value, const char* name)
|
||||
return value != -1 || !PyErr_Occurred();
|
||||
}
|
||||
|
||||
#if defined (_M_AMD64) || defined (__x86_64__)
|
||||
template<>
|
||||
PyObject* pyopencv_from(const unsigned int& value)
|
||||
{
|
||||
return PyLong_FromUnsignedLong(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
bool pyopencv_to(PyObject* obj, unsigned int& value, const char* name)
|
||||
{
|
||||
(void)name;
|
||||
if(!obj || obj == Py_None)
|
||||
return true;
|
||||
if(PyInt_Check(obj))
|
||||
value = (unsigned int)PyInt_AsLong(obj);
|
||||
else if(PyLong_Check(obj))
|
||||
value = (unsigned int)PyLong_AsLong(obj);
|
||||
else
|
||||
return false;
|
||||
return value != (unsigned int)-1 || !PyErr_Occurred();
|
||||
}
|
||||
#endif
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const uchar& value)
|
||||
{
|
||||
@@ -1913,7 +2036,15 @@ void initcv2()
|
||||
|
||||
PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION));
|
||||
|
||||
opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, NULL);
|
||||
PyObject *opencv_error_dict = PyDict_New();
|
||||
PyDict_SetItemString(opencv_error_dict, "file", Py_None);
|
||||
PyDict_SetItemString(opencv_error_dict, "func", Py_None);
|
||||
PyDict_SetItemString(opencv_error_dict, "line", Py_None);
|
||||
PyDict_SetItemString(opencv_error_dict, "code", Py_None);
|
||||
PyDict_SetItemString(opencv_error_dict, "msg", Py_None);
|
||||
PyDict_SetItemString(opencv_error_dict, "err", Py_None);
|
||||
opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, opencv_error_dict);
|
||||
Py_DECREF(opencv_error_dict);
|
||||
PyDict_SetItemString(d, "error", opencv_error);
|
||||
|
||||
//Registering UMatWrapper python class in cv2 module:
|
||||
|
||||
+58
-17
@@ -81,16 +81,25 @@ template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name)
|
||||
{
|
||||
if(!src || src == Py_None)
|
||||
return true;
|
||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
{
|
||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||
return false;
|
||||
dst = ((pyopencv_${name}_t*)src)->v;
|
||||
return true;
|
||||
}
|
||||
dst = ((pyopencv_${name}_t*)src)->v;
|
||||
return true;
|
||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||
return false;
|
||||
}
|
||||
""" % head_init_str)
|
||||
|
||||
gen_template_mappable = Template("""
|
||||
{
|
||||
${mappable} _src;
|
||||
if (pyopencv_to(src, _src, name))
|
||||
{
|
||||
return cv_mappable_to(_src, dst);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
gen_template_type_decl = Template("""
|
||||
struct pyopencv_${name}_t
|
||||
@@ -124,13 +133,14 @@ template<> bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name)
|
||||
{
|
||||
if(!src || src == Py_None)
|
||||
return true;
|
||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
{
|
||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||
return false;
|
||||
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
|
||||
return true;
|
||||
}
|
||||
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
|
||||
return true;
|
||||
${mappable_code}
|
||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
""" % head_init_str)
|
||||
@@ -267,6 +277,7 @@ class ClassInfo(object):
|
||||
self.isalgorithm = False
|
||||
self.methods = {}
|
||||
self.props = []
|
||||
self.mappables = []
|
||||
self.consts = {}
|
||||
self.base = None
|
||||
self.constructor = None
|
||||
@@ -412,10 +423,11 @@ class ArgInfo(object):
|
||||
|
||||
|
||||
class FuncVariant(object):
|
||||
def __init__(self, classname, name, decl, isconstructor):
|
||||
def __init__(self, classname, name, decl, isconstructor, isphantom=False):
|
||||
self.classname = classname
|
||||
self.name = self.wname = name
|
||||
self.isconstructor = isconstructor
|
||||
self.isphantom = isphantom
|
||||
|
||||
self.docstring = decl[5]
|
||||
|
||||
@@ -531,8 +543,8 @@ class FuncInfo(object):
|
||||
self.isclassmethod = isclassmethod
|
||||
self.variants = []
|
||||
|
||||
def add_variant(self, decl):
|
||||
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor))
|
||||
def add_variant(self, decl, isphantom=False):
|
||||
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
|
||||
|
||||
def get_wrapper_name(self):
|
||||
name = self.name
|
||||
@@ -640,6 +652,9 @@ class FuncInfo(object):
|
||||
all_cargs = []
|
||||
parse_arglist = []
|
||||
|
||||
if v.isphantom and ismethod and not self.isclassmethod:
|
||||
code_args += "_self_"
|
||||
|
||||
# declare all the C function arguments,
|
||||
# add necessary conversions from Python objects to code_cvt_list,
|
||||
# form the function/method call,
|
||||
@@ -664,6 +679,9 @@ class FuncInfo(object):
|
||||
if tp.endswith("*"):
|
||||
defval0 = "0"
|
||||
tp1 = tp.replace("*", "_ptr")
|
||||
tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
|
||||
if any(tp in codegen.enum_types for tp in tp_candidates):
|
||||
defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
|
||||
|
||||
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
|
||||
parse_name = a.name
|
||||
@@ -714,6 +732,8 @@ class FuncInfo(object):
|
||||
|
||||
code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
|
||||
code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, args=code_args)
|
||||
if v.isphantom:
|
||||
code_fcall = code_fcall.replace("new " + selfinfo.cname, self.cname.replace("::", "_"))
|
||||
else:
|
||||
code_prelude = ""
|
||||
code_fcall = ""
|
||||
@@ -835,6 +855,7 @@ class PythonWrapperGenerator(object):
|
||||
self.classes = {}
|
||||
self.namespaces = {}
|
||||
self.consts = {}
|
||||
self.enum_types = []
|
||||
self.code_include = StringIO()
|
||||
self.code_types = StringIO()
|
||||
self.code_funcs = StringIO()
|
||||
@@ -892,6 +913,10 @@ class PythonWrapperGenerator(object):
|
||||
py_signatures.append(dict(name=py_name, value=value))
|
||||
#print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
|
||||
|
||||
def add_enum(self, name, decl):
|
||||
enumname = normalize_class_name(name)
|
||||
self.enum_types.append(enumname)
|
||||
|
||||
def add_func(self, decl):
|
||||
namespace, classes, barename = self.split_decl_name(decl[0])
|
||||
cname = "::".join(namespace+classes+[barename])
|
||||
@@ -905,11 +930,21 @@ class PythonWrapperGenerator(object):
|
||||
|
||||
isconstructor = name == bareclassname
|
||||
isclassmethod = False
|
||||
isphantom = False
|
||||
mappable = None
|
||||
for m in decl[2]:
|
||||
if m == "/S":
|
||||
isclassmethod = True
|
||||
elif m == "/phantom":
|
||||
isphantom = True
|
||||
cname = cname.replace("::", "_")
|
||||
elif m.startswith("="):
|
||||
name = m[1:]
|
||||
elif m.startswith("/mappable="):
|
||||
mappable = m[10:]
|
||||
self.classes[classname].mappables.append(mappable)
|
||||
return
|
||||
|
||||
if isconstructor:
|
||||
name = "_".join(classes[:-1]+[name])
|
||||
|
||||
@@ -917,13 +952,13 @@ class PythonWrapperGenerator(object):
|
||||
# Add it as a method to the class
|
||||
func_map = self.classes[classname].methods
|
||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
|
||||
func.add_variant(decl)
|
||||
func.add_variant(decl, isphantom)
|
||||
|
||||
# Add it as global function
|
||||
g_name = "_".join(classes+[name])
|
||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||
func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False))
|
||||
func.add_variant(decl)
|
||||
func.add_variant(decl, isphantom)
|
||||
else:
|
||||
if classname and not isconstructor:
|
||||
cname = barename
|
||||
@@ -932,7 +967,7 @@ class PythonWrapperGenerator(object):
|
||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||
|
||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
|
||||
func.add_variant(decl)
|
||||
func.add_variant(decl, isphantom)
|
||||
|
||||
if classname and isconstructor:
|
||||
self.classes[classname].constructor = func
|
||||
@@ -996,6 +1031,9 @@ class PythonWrapperGenerator(object):
|
||||
elif name.startswith("const"):
|
||||
# constant
|
||||
self.add_const(name.replace("const ", "").strip(), decl)
|
||||
elif name.startswith("enum"):
|
||||
# enum
|
||||
self.add_enum(name.replace("enum ", "").strip(), decl)
|
||||
else:
|
||||
# function
|
||||
self.add_func(decl)
|
||||
@@ -1045,8 +1083,11 @@ class PythonWrapperGenerator(object):
|
||||
templ = gen_template_simple_type_decl
|
||||
else:
|
||||
templ = gen_template_type_decl
|
||||
mappable_code = "\n".join([
|
||||
gen_template_mappable.substitute(cname=classinfo.cname, mappable=mappable)
|
||||
for mappable in classinfo.mappables])
|
||||
self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname, sname=classinfo.sname,
|
||||
cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname)))
|
||||
cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname), mappable_code=mappable_code))
|
||||
|
||||
# register classes in the same order as they have been declared.
|
||||
# this way, base classes will be registered in Python before their derivatives.
|
||||
|
||||
@@ -6,6 +6,7 @@ import os, sys, re, string, io
|
||||
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
|
||||
opencv_hdr_list = [
|
||||
"../../core/include/opencv2/core.hpp",
|
||||
"../../core/include/opencv2/core/mat.hpp",
|
||||
"../../core/include/opencv2/core/ocl.hpp",
|
||||
"../../flann/include/opencv2/flann/miniflann.hpp",
|
||||
"../../ml/include/opencv2/ml.hpp",
|
||||
@@ -376,8 +377,6 @@ class CppHeaderParser(object):
|
||||
decl[2].append("/A")
|
||||
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
|
||||
decl[2].append("/C")
|
||||
if "virtual" in decl_str:
|
||||
print(decl_str)
|
||||
return decl
|
||||
|
||||
def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
|
||||
@@ -393,8 +392,7 @@ class CppHeaderParser(object):
|
||||
"""
|
||||
|
||||
if self.wrap_mode:
|
||||
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
|
||||
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
|
||||
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
|
||||
return []
|
||||
|
||||
# ignore old API in the documentation check (for now)
|
||||
@@ -414,6 +412,16 @@ class CppHeaderParser(object):
|
||||
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("="+arg)
|
||||
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
||||
npos = decl_str.find("CV_WRAP_PHANTOM")
|
||||
if npos >= 0:
|
||||
decl_str, _ = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("/phantom")
|
||||
npos = decl_str.find("CV_WRAP_MAPPABLE")
|
||||
if npos >= 0:
|
||||
mappable, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("/mappable="+mappable)
|
||||
classname = top[1]
|
||||
return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
|
||||
|
||||
virtual_method = False
|
||||
pure_virtual_method = False
|
||||
@@ -527,8 +535,6 @@ class CppHeaderParser(object):
|
||||
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
||||
if not t:
|
||||
print("Error: no closing ')' at %d" % (self.lineno,))
|
||||
print(decl_str)
|
||||
print(decl_str[arg_start:])
|
||||
sys.exit(-1)
|
||||
if t == "<":
|
||||
angle_balance += 1
|
||||
@@ -705,20 +711,19 @@ class CppHeaderParser(object):
|
||||
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
|
||||
return stmt_type, classname, True, decl
|
||||
|
||||
if stmt.startswith("enum"):
|
||||
return "enum", "", True, None
|
||||
|
||||
if stmt.startswith("namespace"):
|
||||
if stmt.startswith("enum") or stmt.startswith("namespace"):
|
||||
stmt_list = stmt.split()
|
||||
if len(stmt_list) < 2:
|
||||
stmt_list.append("<unnamed>")
|
||||
return stmt_list[0], stmt_list[1], True, None
|
||||
|
||||
if stmt.startswith("extern") and "\"C\"" in stmt:
|
||||
return "namespace", "", True, None
|
||||
|
||||
if end_token == "}" and context == "enum":
|
||||
decl = self.parse_enum(stmt)
|
||||
return "enum", "", False, decl
|
||||
name = stack_top[self.BLOCK_NAME]
|
||||
return "enum", name, False, decl
|
||||
|
||||
if end_token == ";" and stmt.startswith("typedef"):
|
||||
# TODO: handle typedef's more intelligently
|
||||
@@ -896,8 +901,9 @@ class CppHeaderParser(object):
|
||||
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
|
||||
if decl:
|
||||
if stmt_type == "enum":
|
||||
for d in decl:
|
||||
decls.append(d)
|
||||
if name != "<unnamed>":
|
||||
decls.append(["enum " + self.get_dotted_name(name), "", [], [], None, ""])
|
||||
decls.extend(decl)
|
||||
else:
|
||||
decls.append(decl)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user