mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -04:00
interrogate: nullptr handling, faster kwargs handling in some cases
This commit is contained in:
parent
652f2d7f21
commit
a387fb9f35
@ -869,8 +869,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
}
|
||||
|
||||
if (_args_type == InterfaceMaker::AT_varargs) {
|
||||
// Of course methods named "make" can still take kwargs.
|
||||
_args_type = InterfaceMaker::AT_keyword_args;
|
||||
// Of course methods named "make" can still take kwargs, if they are
|
||||
// named.
|
||||
for (int i = first_param; i < _parameters.size(); ++i) {
|
||||
if (_parameters[i]._has_name) {
|
||||
_args_type = InterfaceMaker::AT_keyword_args;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (fname == "operator /") {
|
||||
@ -898,8 +904,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
} else {
|
||||
if (_args_type == InterfaceMaker::AT_varargs) {
|
||||
// Every other method can take keyword arguments, if they take more
|
||||
// than one argument.
|
||||
_args_type |= InterfaceMaker::AT_keyword_args;
|
||||
// than one argument, and the arguments are named.
|
||||
for (int i = first_param; i < _parameters.size(); ++i) {
|
||||
if (_parameters[i]._has_name) {
|
||||
_args_type |= InterfaceMaker::AT_keyword_args;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -941,8 +952,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
_flags |= F_coerce_constructor;
|
||||
}
|
||||
|
||||
// Constructors always take varargs and keyword args.
|
||||
_args_type = InterfaceMaker::AT_keyword_args;
|
||||
// Constructors always take varargs, and possibly keyword args.
|
||||
_args_type = InterfaceMaker::AT_varargs;
|
||||
for (int i = first_param; i < _parameters.size(); ++i) {
|
||||
if (_parameters[i]._has_name) {
|
||||
_args_type = InterfaceMaker::AT_keyword_args;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3389,6 +3389,7 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
FunctionRemap *remap = NULL;
|
||||
int max_required_args = 0;
|
||||
bool all_nonconst = true;
|
||||
bool has_keywords = false;
|
||||
|
||||
out << "/**\n * Python function wrapper for:\n";
|
||||
for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
|
||||
@ -3404,6 +3405,10 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
all_nonconst = false;
|
||||
}
|
||||
|
||||
if (remap->_args_type == AT_keyword_args) {
|
||||
has_keywords = true;
|
||||
}
|
||||
|
||||
max_required_args = max(max_num_args, max_required_args);
|
||||
|
||||
for (int i = min_num_args; i <= max_num_args; ++i) {
|
||||
@ -3450,6 +3455,19 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
return;
|
||||
}
|
||||
|
||||
if (args_type == AT_keyword_args && !has_keywords) {
|
||||
// We don't actually take keyword arguments. Make sure we didn't get any.
|
||||
out << " if (kwds != NULL && PyDict_Size(kwds) > 0) {\n";
|
||||
out << "#ifdef NDEBUG\n";
|
||||
error_raise_return(out, 4, return_flags, "TypeError", "function takes no keyword arguments");
|
||||
out << "#else\n";
|
||||
error_raise_return(out, 4, return_flags, "TypeError",
|
||||
methodNameFromCppName(remap, "", false) + "() takes no keyword arguments");
|
||||
out << "#endif\n";
|
||||
out << " }\n";
|
||||
args_type = AT_varargs;
|
||||
}
|
||||
|
||||
if (args_type == AT_keyword_args || args_type == AT_varargs) {
|
||||
max_required_args = collapse_default_remaps(map_sets, max_required_args);
|
||||
}
|
||||
@ -3461,6 +3479,7 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
args_type, return_flags);
|
||||
|
||||
} else if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) {
|
||||
// We have more than one remap.
|
||||
switch (args_type) {
|
||||
case AT_keyword_args:
|
||||
indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n";
|
||||
@ -3498,16 +3517,50 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
indent(out, 2) << "case " << i << ":\n";
|
||||
num_args.insert(i + add_self);
|
||||
}
|
||||
indent(out, 4) << "{\n";
|
||||
num_args.insert(max_args + add_self);
|
||||
|
||||
if (min_args == 1 && max_args == 1 && args_type == AT_varargs) {
|
||||
// Might as well, since we already checked the number of args.
|
||||
indent(out, 6) << " PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
|
||||
bool strip_keyword_args = false;
|
||||
|
||||
// Check whether any remap actually takes keyword arguments. If not,
|
||||
// then we don't have to bother checking that for every remap.
|
||||
if (args_type == AT_keyword_args && max_args > 0) {
|
||||
strip_keyword_args = true;
|
||||
|
||||
std::set<FunctionRemap *>::iterator sii;
|
||||
for (sii = mii->second.begin(); sii != mii->second.end(); ++sii) {
|
||||
remap = (*sii);
|
||||
int first_param = remap->_has_this ? 1 : 0;
|
||||
for (int i = first_param; i < remap->_parameters.size(); ++i) {
|
||||
if (remap->_parameters[i]._has_name) {
|
||||
strip_keyword_args = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strip_keyword_args) {
|
||||
// None of the remaps take any keyword arguments, so let's check that
|
||||
// we take none. This saves some checks later on.
|
||||
indent(out, 4) << "if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {\n";
|
||||
if (min_args == 1 && min_args == 1) {
|
||||
indent(out, 4) << " PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
|
||||
write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
|
||||
coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
|
||||
} else {
|
||||
write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
|
||||
coercion_allowed, true, AT_varargs, return_flags, true, !all_nonconst);
|
||||
}
|
||||
} else if (min_args == 1 && max_args == 1 && args_type == AT_varargs) {
|
||||
// We already checked that the args tuple has only one argument, so
|
||||
// we might as well extract that from the tuple now.
|
||||
indent(out, 4) << "{\n";
|
||||
indent(out, 4) << " PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
|
||||
|
||||
write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
|
||||
coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
|
||||
} else {
|
||||
indent(out, 4) << "{\n";
|
||||
write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
|
||||
coercion_allowed, true, args_type, return_flags, true, !all_nonconst);
|
||||
}
|
||||
@ -3574,14 +3627,14 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
if (mii->first == 0 && args_type != AT_no_args) {
|
||||
switch (args_type) {
|
||||
case AT_keyword_args:
|
||||
out << " if (PyTuple_Size(args) > 0 || (kwds != NULL && PyDict_Size(kwds) > 0)) {\n";
|
||||
out << " if (!Dtool_CheckNoArgs(args, kwds)) {\n";
|
||||
out << " int parameter_count = (int)PyTuple_Size(args);\n";
|
||||
out << " if (kwds != NULL) {\n";
|
||||
out << " parameter_count += (int)PyDict_Size(kwds);\n";
|
||||
out << " }\n";
|
||||
break;
|
||||
case AT_varargs:
|
||||
out << " if (PyTuple_Size(args) > 0) {\n";
|
||||
out << " if (!Dtool_CheckNoArgs(args)) {\n";
|
||||
out << " const int parameter_count = (int)PyTuple_GET_SIZE(args);\n";
|
||||
break;
|
||||
case AT_single_arg:
|
||||
@ -3607,14 +3660,14 @@ write_function_for_name(ostream &out, Object *obj,
|
||||
} else if (args_type == AT_keyword_args && max_required_args == 1 && mii->first == 1) {
|
||||
// Check this to be sure, as we handle the case of only 1 keyword arg in
|
||||
// write_function_forset (not using ParseTupleAndKeywords).
|
||||
out << " int parameter_count = (int)PyTuple_Size(args);\n"
|
||||
" if (kwds != NULL) {\n"
|
||||
" parameter_count += (int)PyDict_Size(kwds);\n"
|
||||
" }\n"
|
||||
out << " int parameter_count = (int)PyTuple_Size(args);\n"
|
||||
" if (kwds != NULL) {\n"
|
||||
" parameter_count += (int)PyDict_Size(kwds);\n"
|
||||
" }\n"
|
||||
" if (parameter_count != 1) {\n"
|
||||
"#ifdef NDEBUG\n";
|
||||
error_raise_return(out, 4, return_flags, "TypeError",
|
||||
"function takes exactly 1 argument");
|
||||
"function takes exactly 1 argument");
|
||||
out << "#else\n";
|
||||
error_raise_return(out, 4, return_flags, "TypeError",
|
||||
methodNameFromCppName(remap, "", false) + "() takes exactly 1 argument (%d given)",
|
||||
@ -4067,7 +4120,9 @@ int get_type_sort(CPPType *type) {
|
||||
// printf(" %s\n",type->get_local_name().c_str());
|
||||
|
||||
// The highest numbered one will be checked first.
|
||||
if (TypeManager::is_pointer_to_Py_buffer(type)) {
|
||||
if (TypeManager::is_nullptr(type)) {
|
||||
return 15;
|
||||
} else if (TypeManager::is_pointer_to_Py_buffer(type)) {
|
||||
return 14;
|
||||
} else if (TypeManager::is_pointer_to_PyTypeObject(type)) {
|
||||
return 13;
|
||||
@ -4247,14 +4302,16 @@ write_function_forset(ostream &out,
|
||||
args_type == AT_keyword_args) {
|
||||
sii = remapsin.begin();
|
||||
remap = (*sii);
|
||||
first_param_name = remap->_parameters[(int)remap->_has_this]._name;
|
||||
same_first_param = true;
|
||||
if (remap->_parameters[(int)remap->_has_this]._has_name) {
|
||||
first_param_name = remap->_parameters[(int)remap->_has_this]._name;
|
||||
same_first_param = true;
|
||||
|
||||
for (++sii; sii != remapsin.end(); ++sii) {
|
||||
remap = (*sii);
|
||||
if (remap->_parameters[(int)remap->_has_this]._name != first_param_name) {
|
||||
same_first_param = false;
|
||||
break;
|
||||
for (++sii; sii != remapsin.end(); ++sii) {
|
||||
remap = (*sii);
|
||||
if (remap->_parameters[(int)remap->_has_this]._name != first_param_name) {
|
||||
same_first_param = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4263,21 +4320,9 @@ write_function_forset(ostream &out,
|
||||
// Yes, they all have the same argument name (or there is only one remap).
|
||||
// Extract it from the dict so we don't have to call
|
||||
// ParseTupleAndKeywords.
|
||||
indent(out, indent_level) << "PyObject *arg = NULL;\n";
|
||||
indent(out, indent_level) << "if (PyTuple_GET_SIZE(args) == 1) {\n";
|
||||
indent(out, indent_level) << " arg = PyTuple_GET_ITEM(args, 0);\n";
|
||||
indent(out, indent_level) << "} else if (kwds != NULL) {\n";
|
||||
indent(out, indent_level) << " arg = PyDict_GetItemString(kwds, \"" << first_param_name << "\");\n";
|
||||
indent(out, indent_level) << "}\n";
|
||||
if (report_errors) {
|
||||
indent(out, indent_level) << "if (arg == (PyObject *)NULL) {\n";
|
||||
error_raise_return(out, indent_level + 2, return_flags, "TypeError",
|
||||
"Required argument '" + first_param_name + "' (pos 1) not found");
|
||||
indent(out, indent_level) << "}\n";
|
||||
} else {
|
||||
indent(out, indent_level) << "if (arg != (PyObject *)NULL) {\n";
|
||||
indent_level += 2;
|
||||
}
|
||||
indent(out, indent_level) << "PyObject *arg;\n";
|
||||
indent(out, indent_level) << "if (Dtool_ExtractArg(&arg, args, kwds, \"" << first_param_name << "\")) {\n";
|
||||
indent_level += 2;
|
||||
args_type = AT_single_arg;
|
||||
}
|
||||
|
||||
@ -4448,7 +4493,7 @@ write_function_forset(ostream &out,
|
||||
}
|
||||
|
||||
// Close the brace we opened earlier.
|
||||
if (same_first_param && !report_errors) {
|
||||
if (same_first_param) {
|
||||
indent_level -= 2;
|
||||
indent(out, indent_level) << "}\n";
|
||||
}
|
||||
@ -4517,6 +4562,8 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
string parameter_list;
|
||||
string container;
|
||||
string type_check;
|
||||
string param_name;
|
||||
bool has_keywords = false;
|
||||
vector_string pexprs;
|
||||
LineStream extra_convert;
|
||||
ostringstream extra_param_check;
|
||||
@ -4612,7 +4659,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
CPPType *orig_type = param->get_orig_type();
|
||||
CPPType *type = param->get_new_type();
|
||||
CPPExpression *default_value = param->get_default_value();
|
||||
string param_name = remap->get_parameter_name(pn);
|
||||
param_name = remap->get_parameter_name(pn);
|
||||
|
||||
if (!is_cpp_type_legal(orig_type)) {
|
||||
// We can't wrap this. We sometimes get here for default arguments.
|
||||
@ -4667,7 +4714,14 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
}
|
||||
|
||||
string reported_name = remap->_parameters[pn]._name;
|
||||
keyword_list += "\"" + reported_name + "\", ";
|
||||
if (!keyword_list.empty()) {
|
||||
keyword_list += ", \"" + reported_name + "\"";
|
||||
} else {
|
||||
keyword_list = "\"" + reported_name + "\"";
|
||||
}
|
||||
if (remap->_parameters[pn]._has_name) {
|
||||
has_keywords = true;
|
||||
}
|
||||
|
||||
if (param->new_type_is_atomic_string()) {
|
||||
|
||||
@ -4869,6 +4923,19 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
pexpr_string = "(PyObject_IsTrue(" + param_name + ") != 0)";
|
||||
expected_params += "bool";
|
||||
|
||||
} else if (TypeManager::is_nullptr(type)) {
|
||||
if (args_type == AT_single_arg) {
|
||||
type_check = "arg == Py_None";
|
||||
param_name = "arg";
|
||||
} else {
|
||||
indent(out, indent_level) << "PyObject *" << param_name << default_expr << ";\n";
|
||||
extra_param_check << " && " << param_name << " == Py_None";
|
||||
format_specifiers += "O";
|
||||
parameter_list += ", &" + param_name;
|
||||
}
|
||||
pexpr_string = "NULL";
|
||||
expected_params += "NoneType";
|
||||
|
||||
} else if (TypeManager::is_char(type)) {
|
||||
indent(out, indent_level) << "char " << param_name << default_expr << ";\n";
|
||||
|
||||
@ -4907,27 +4974,43 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
only_pyobjects = false;
|
||||
|
||||
} else if (TypeManager::is_size(type)) {
|
||||
// It certainly isn't the exact same thing as size_t, but Py_ssize_t
|
||||
// should at least be the same size. The problem with mapping this to
|
||||
// unsigned int is that that doesn't work well on 64-bit systems, on
|
||||
// which size_t is a 64-bit integer.
|
||||
indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n";
|
||||
format_specifiers += "n";
|
||||
parameter_list += ", &" + param_name;
|
||||
if (args_type == AT_single_arg) {
|
||||
type_check = "PyLongOrInt_Check(arg)";
|
||||
|
||||
extra_convert <<
|
||||
"size_t arg_val = PyLongOrInt_AsSize_t(arg);\n"
|
||||
"#ifndef NDEBUG\n"
|
||||
"if (arg_val == (size_t)-1 && _PyErr_OCCURRED()) {\n";
|
||||
error_return(extra_convert, 2, return_flags);
|
||||
extra_convert <<
|
||||
"}\n"
|
||||
"#endif\n";
|
||||
|
||||
pexpr_string = "arg_val";
|
||||
|
||||
} else {
|
||||
// It certainly isn't the exact same thing as size_t, but Py_ssize_t
|
||||
// should at least be the same size. The problem with mapping this to
|
||||
// unsigned int is that that doesn't work well on 64-bit systems, on
|
||||
// which size_t is a 64-bit integer.
|
||||
indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n";
|
||||
format_specifiers += "n";
|
||||
parameter_list += ", &" + param_name;
|
||||
|
||||
extra_convert
|
||||
<< "#ifndef NDEBUG\n"
|
||||
<< "if (" << param_name << " < 0) {\n";
|
||||
|
||||
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
|
||||
"can't convert negative value %zd to size_t",
|
||||
param_name);
|
||||
extra_convert
|
||||
<< "}\n"
|
||||
<< "#endif\n";
|
||||
}
|
||||
expected_params += "int";
|
||||
only_pyobjects = false;
|
||||
|
||||
extra_convert
|
||||
<< "#ifndef NDEBUG\n"
|
||||
<< "if (" << param_name << " < 0) {\n";
|
||||
|
||||
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
|
||||
"can't convert negative value %zd to size_t",
|
||||
param_name);
|
||||
extra_convert
|
||||
<< "}\n"
|
||||
<< "#endif\n";
|
||||
|
||||
} else if (TypeManager::is_longlong(type)) {
|
||||
// It's not trivial to do overflow checking for a long long, so we
|
||||
// simply don't do it.
|
||||
@ -5555,15 +5638,60 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
switch (args_type) {
|
||||
case AT_keyword_args:
|
||||
// Wrapper takes a varargs tuple and a keyword args dict.
|
||||
indent(out, indent_level)
|
||||
<< "static const char *keyword_list[] = {" << keyword_list << "NULL};\n";
|
||||
indent(out, indent_level)
|
||||
<< "if (PyArg_ParseTupleAndKeywords(args, kwds, \""
|
||||
<< format_specifiers << ":" << method_name
|
||||
<< "\", (char **)keyword_list" << parameter_list << ")) {\n";
|
||||
if (has_keywords) {
|
||||
if (only_pyobjects && max_num_args == 1) {
|
||||
// But we are only expecting one object arg, which is an easy common
|
||||
// case we have implemented ourselves.
|
||||
if (min_num_args == 1) {
|
||||
indent(out, indent_level)
|
||||
<< "if (Dtool_ExtractArg(&" << param_name << ", args, kwds, " << keyword_list << ")) {\n";
|
||||
} else {
|
||||
indent(out, indent_level)
|
||||
<< "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds, " << keyword_list << ")) {\n";
|
||||
}
|
||||
} else {
|
||||
// We have to use the more expensive PyArg_ParseTupleAndKeywords.
|
||||
clear_error = true;
|
||||
indent(out, indent_level)
|
||||
<< "static const char *keyword_list[] = {" << keyword_list << ", NULL};\n";
|
||||
indent(out, indent_level)
|
||||
<< "if (PyArg_ParseTupleAndKeywords(args, kwds, \""
|
||||
<< format_specifiers << ":" << method_name
|
||||
<< "\", (char **)keyword_list" << parameter_list << ")) {\n";
|
||||
}
|
||||
|
||||
} else if (only_pyobjects) {
|
||||
// This function actually has no named parameters, so let's not take
|
||||
// any keyword arguments.
|
||||
if (max_num_args == 1) {
|
||||
if (min_num_args == 1) {
|
||||
indent(out, indent_level)
|
||||
<< "if (Dtool_ExtractArg(&" << param_name << ", args, kwds)) {\n";
|
||||
} else {
|
||||
indent(out, indent_level)
|
||||
<< "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds)) {\n";
|
||||
}
|
||||
} else if (max_num_args == 0) {
|
||||
indent(out, indent_level)
|
||||
<< "if (Dtool_CheckNoArgs(args, kwds)) {\n";
|
||||
} else {
|
||||
clear_error = true;
|
||||
indent(out, indent_level)
|
||||
<< "if ((kwds == NULL || PyDict_Size(kwds) == 0) && PyArg_UnpackTuple(args, \""
|
||||
<< methodNameFromCppName(remap, "", false)
|
||||
<< "\", " << min_num_args << ", " << max_num_args
|
||||
<< parameter_list << ")) {\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
clear_error = true;
|
||||
indent(out, indent_level)
|
||||
<< "if ((kwds == NULL || PyDict_Size(kwds) == 0) && PyArg_ParseTuple(args, \""
|
||||
<< format_specifiers << ":" << method_name
|
||||
<< "\"" << parameter_list << ")) {\n";
|
||||
}
|
||||
|
||||
++open_scopes;
|
||||
clear_error = true;
|
||||
indent_level += 2;
|
||||
break;
|
||||
|
||||
@ -5572,20 +5700,28 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
||||
if (only_pyobjects) {
|
||||
// All parameters are PyObject*, so we can use the slightly more
|
||||
// efficient PyArg_UnpackTuple function instead.
|
||||
indent(out, indent_level)
|
||||
<< "if (PyArg_UnpackTuple(args, \""
|
||||
<< methodNameFromCppName(remap, "", false)
|
||||
<< "\", " << min_num_args << ", " << max_num_args
|
||||
<< parameter_list << ")) {\n";
|
||||
if (min_num_args == 1 && max_num_args == 1) {
|
||||
indent(out, indent_level)
|
||||
<< "if (PyTuple_GET_SIZE(args) == 1) {\n";
|
||||
indent(out, indent_level + 2)
|
||||
<< param_name << " = PyTuple_GET_ITEM(args, 0);\n";
|
||||
} else {
|
||||
clear_error = true;
|
||||
indent(out, indent_level)
|
||||
<< "if (PyArg_UnpackTuple(args, \""
|
||||
<< methodNameFromCppName(remap, "", false)
|
||||
<< "\", " << min_num_args << ", " << max_num_args
|
||||
<< parameter_list << ")) {\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
clear_error = true;
|
||||
indent(out, indent_level)
|
||||
<< "if (PyArg_ParseTuple(args, \""
|
||||
<< format_specifiers << ":" << method_name
|
||||
<< "\"" << parameter_list << ")) {\n";
|
||||
}
|
||||
++open_scopes;
|
||||
clear_error = true;
|
||||
indent_level += 2;
|
||||
break;
|
||||
|
||||
|
@ -2346,6 +2346,10 @@ define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) {
|
||||
itype._atomic_token = AT_void;
|
||||
break;
|
||||
|
||||
case CPPSimpleType::T_nullptr:
|
||||
itype._atomic_token = AT_null;
|
||||
break;
|
||||
|
||||
default:
|
||||
nout << "Type \"" << *cpptype << "\" has invalid CPPSimpleType: "
|
||||
<< (int)cpptype->_type << "\n";
|
||||
|
@ -364,6 +364,27 @@ is_const_ref_to_enum(CPPType *type) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the indicated type is nullptr_t, possibly const or a
|
||||
* typedef to it.
|
||||
*/
|
||||
bool TypeManager::
|
||||
is_nullptr(CPPType *type) {
|
||||
switch (type->get_subtype()) {
|
||||
case CPPDeclaration::ST_simple:
|
||||
return type->as_simple_type()->_type == CPPSimpleType::T_nullptr;
|
||||
|
||||
case CPPDeclaration::ST_const:
|
||||
return is_nullptr(type->as_const_type()->_wrapped_around);
|
||||
|
||||
case CPPDeclaration::ST_typedef:
|
||||
return is_nullptr(type->as_typedef_type()->_type);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the indicated type is something that a scripting language
|
||||
* can handle directly as a concrete, like an int or float, either const or
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
static bool is_enum(CPPType *type);
|
||||
static bool is_const_enum(CPPType *type);
|
||||
static bool is_const_ref_to_enum(CPPType *type);
|
||||
static bool is_nullptr(CPPType *type);
|
||||
static bool is_simple(CPPType *type);
|
||||
static bool is_const_simple(CPPType *type);
|
||||
static bool is_const_ref_to_simple(CPPType *type);
|
||||
|
@ -82,7 +82,11 @@ enum AtomicToken {
|
||||
// string means whatever the native string representation is.
|
||||
AT_string = 7,
|
||||
|
||||
AT_longlong = 8
|
||||
AT_longlong = 8,
|
||||
|
||||
// This is not a type that C has, but C++ and many scripting languages do;
|
||||
// it indicates a null value, or the absence of any value.
|
||||
AT_null = 9,
|
||||
};
|
||||
|
||||
EXPCL_INTERROGATEDB void interrogate_add_search_directory(const char *dirname);
|
||||
|
@ -59,6 +59,23 @@ DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
|
||||
return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the tuple is empty.
|
||||
*/
|
||||
ALWAYS_INLINE bool
|
||||
Dtool_CheckNoArgs(PyObject *args) {
|
||||
return PyTuple_GET_SIZE(args) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the tuple is empty, and that the dict is empty or NULL.
|
||||
*/
|
||||
ALWAYS_INLINE bool
|
||||
Dtool_CheckNoArgs(PyObject *args, PyObject *kwds) {
|
||||
return PyTuple_GET_SIZE(args) == 0 &&
|
||||
(kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The following functions wrap an arbitrary C++ value into a PyObject.
|
||||
*/
|
||||
@ -196,6 +213,11 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value) {
|
||||
return PyUnicode_FromWideChar(&value, 1);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value) {
|
||||
return value;
|
||||
}
|
||||
|
@ -31,6 +31,49 @@ static RuntimeTypeMap runtime_type_map;
|
||||
static RuntimeTypeSet runtime_type_set;
|
||||
static NamedTypeMap named_type_map;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
/**
|
||||
* Given a long or int, returns a size_t, or raises an OverflowError if it is
|
||||
* out of range.
|
||||
*/
|
||||
size_t PyLongOrInt_AsSize_t(PyObject *vv) {
|
||||
if (PyInt_Check(vv)) {
|
||||
long value = PyInt_AS_LONG(vv);
|
||||
if (value < 0) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"can't convert negative value to size_t");
|
||||
return (size_t)-1;
|
||||
}
|
||||
return (size_t)value;
|
||||
}
|
||||
|
||||
if (!PyLong_Check(vv)) {
|
||||
PyErr_BadInternalCall();
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
size_t bytes;
|
||||
int one = 1;
|
||||
int res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
|
||||
SIZEOF_SIZE_T, (int)*(unsigned char*)&one, 0);
|
||||
|
||||
if (res < 0) {
|
||||
return (size_t)res;
|
||||
} else {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x03060000
|
||||
INLINE static PyObject *_PyObject_CallNoArg(PyObject *func) {
|
||||
PyObject *args = PyTuple_New(0);
|
||||
PyObject *result = PyObject_Call(func, args, NULL);
|
||||
Py_DECREF(args);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Given a valid (non-NULL) PyObject, does a simple check to see if it might
|
||||
* be an instance of a Panda type. It does this using a signature that is
|
||||
@ -767,12 +810,16 @@ int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2) {
|
||||
if (func == NULL) {
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
#if PY_VERSION_HEX >= 0x03060000
|
||||
PyObject *res = _PyObject_FastCall(func, &v2, 1);
|
||||
#else
|
||||
PyObject *res = NULL;
|
||||
PyObject *args = PyTuple_Pack(1, v2);
|
||||
if (args != NULL) {
|
||||
res = PyObject_Call(func, args, NULL);
|
||||
Py_DECREF(args);
|
||||
}
|
||||
#endif
|
||||
Py_DECREF(func);
|
||||
PyErr_Clear(); // just in case the function threw an error
|
||||
// only use if the function returns an INT... hmm
|
||||
@ -844,7 +891,13 @@ PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op) {
|
||||
* make_copy() method.
|
||||
*/
|
||||
PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
|
||||
return PyObject_CallMethod(self, (char *)"make_copy", (char *)"()");
|
||||
PyObject *callable = PyObject_GetAttrString(self, "make_copy");
|
||||
if (callable == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *result = _PyObject_CallNoArg(callable);
|
||||
Py_DECREF(callable);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -852,13 +905,15 @@ PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
|
||||
* copy constructor.
|
||||
*/
|
||||
PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *callable = (PyObject *)Py_TYPE(self);
|
||||
|
||||
PyObject *result = PyObject_CallFunction(this_class, (char *)"(O)", self);
|
||||
Py_DECREF(this_class);
|
||||
#if PY_VERSION_HEX >= 0x03060000
|
||||
PyObject *result = _PyObject_FastCall(callable, &self, 1);
|
||||
#else
|
||||
PyObject *args = PyTuple_Pack(1, self);
|
||||
PyObject *result = PyObject_Call(callable, args, NULL);
|
||||
Py_DECREF(args);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -868,7 +923,109 @@ PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
|
||||
* __copy__().
|
||||
*/
|
||||
PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
|
||||
return PyObject_CallMethod(self, (char *)"__copy__", (char *)"()");
|
||||
PyObject *callable = PyObject_GetAttrString(self, "__copy__");
|
||||
if (callable == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *result = _PyObject_CallNoArg(callable);
|
||||
Py_DECREF(callable);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A more efficient version of PyArg_ParseTupleAndKeywords for the special
|
||||
* case where there is only a single PyObject argument.
|
||||
*/
|
||||
bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds,
|
||||
const char *keyword) {
|
||||
|
||||
if (PyTuple_GET_SIZE(args) == 1) {
|
||||
if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {
|
||||
*result = PyTuple_GET_ITEM(args, 0);
|
||||
return true;
|
||||
}
|
||||
} else if (PyTuple_GET_SIZE(args) == 0) {
|
||||
PyObject *key;
|
||||
Py_ssize_t ppos = 0;
|
||||
if (kwds != NULL && ((PyDictObject *)kwds)->ma_used == 1 &&
|
||||
PyDict_Next(kwds, &ppos, &key, result)) {
|
||||
// We got the item, we just need to make sure that it had the right key.
|
||||
#if PY_VERSION_HEX >= 0x03050000
|
||||
return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword);
|
||||
#elif PY_MAJOR_VERSION >= 3
|
||||
return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0;
|
||||
#else
|
||||
return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of Dtool_ExtractArg that does not accept a keyword argument.
|
||||
*/
|
||||
bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds) {
|
||||
if (PyTuple_GET_SIZE(args) == 1 &&
|
||||
(kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0)) {
|
||||
*result = PyTuple_GET_ITEM(args, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A more efficient version of PyArg_ParseTupleAndKeywords for the special
|
||||
* case where there is only a single optional PyObject argument.
|
||||
*
|
||||
* Returns true if valid (including if there were 0 items), false if there was
|
||||
* an error, such as an invalid number of parameters.
|
||||
*/
|
||||
bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds,
|
||||
const char *keyword) {
|
||||
|
||||
if (PyTuple_GET_SIZE(args) == 1) {
|
||||
if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {
|
||||
*result = PyTuple_GET_ITEM(args, 0);
|
||||
return true;
|
||||
}
|
||||
} else if (PyTuple_GET_SIZE(args) == 0) {
|
||||
if (kwds != NULL && ((PyDictObject *)kwds)->ma_used == 1) {
|
||||
PyObject *key;
|
||||
Py_ssize_t ppos = 0;
|
||||
if (!PyDict_Next(kwds, &ppos, &key, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We got the item, we just need to make sure that it had the right key.
|
||||
#if PY_VERSION_HEX >= 0x03050000
|
||||
return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword);
|
||||
#elif PY_MAJOR_VERSION >= 3
|
||||
return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0;
|
||||
#else
|
||||
return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0;
|
||||
#endif
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of Dtool_ExtractOptionalArg that does not accept a keyword argument.
|
||||
*/
|
||||
bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds) {
|
||||
if (kwds != NULL && ((PyDictObject *)kwds)->ma_used != 0) {
|
||||
return false;
|
||||
}
|
||||
if (PyTuple_GET_SIZE(args) == 1) {
|
||||
*result = PyTuple_GET_ITEM(args, 0);
|
||||
return true;
|
||||
}
|
||||
return (PyTuple_GET_SIZE(args) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,11 +107,14 @@ inline PyObject* doPy_RETURN_FALSE()
|
||||
#define PyInt_Check PyLong_Check
|
||||
#define PyInt_AsLong PyLong_AsLong
|
||||
#define PyInt_AS_LONG PyLong_AS_LONG
|
||||
#define PyLongOrInt_AsSize_t PyLong_AsSize_t
|
||||
#else
|
||||
#define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x))
|
||||
// PyInt_FromSize_t automatically picks the right type.
|
||||
#define PyLongOrInt_AS_LONG PyInt_AsLong
|
||||
|
||||
EXPCL_INTERROGATEDB size_t PyLongOrInt_AsSize_t(PyObject *);
|
||||
|
||||
// For more portably defining hash functions.
|
||||
typedef long Py_hash_t;
|
||||
#endif
|
||||
@ -469,6 +472,21 @@ struct Dtool_SequenceWrapper {
|
||||
|
||||
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
|
||||
|
||||
/**
|
||||
* These functions check whether the arguments passed to a function conform to
|
||||
* certain expectations.
|
||||
*/
|
||||
ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
|
||||
ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
|
||||
EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds, const char *keyword);
|
||||
EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds);
|
||||
EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds, const char *keyword);
|
||||
EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds);
|
||||
|
||||
/**
|
||||
* These functions convert a C++ value into the corresponding Python object.
|
||||
* This used to be generated by the code generator, but it seems more reliable
|
||||
@ -491,6 +509,7 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string *value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring *value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char> &value);
|
||||
|
||||
|
@ -23,7 +23,5 @@
|
||||
|
||||
#define offsetof(type,member) ((size_t) &(((type*)0)->member))
|
||||
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -41,11 +41,7 @@ inline namespace std {
|
||||
|
||||
struct timeval;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0L
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
|
||||
// One day, we might extend interrogate to be able to parse this,
|
||||
// but we currently don't need it.
|
||||
|
@ -32,6 +32,7 @@ extern "C" {
|
||||
EXPCL_PYSTUB int PyDict_GetItem(...);
|
||||
EXPCL_PYSTUB int PyDict_GetItemString(...);
|
||||
EXPCL_PYSTUB int PyDict_New(...);
|
||||
EXPCL_PYSTUB int PyDict_Next(...);
|
||||
EXPCL_PYSTUB int PyDict_SetItem(...);
|
||||
EXPCL_PYSTUB int PyDict_SetItemString(...);
|
||||
EXPCL_PYSTUB int PyDict_Size(...);
|
||||
@ -49,7 +50,6 @@ extern "C" {
|
||||
EXPCL_PYSTUB int PyErr_WarnEx(...);
|
||||
EXPCL_PYSTUB int PyEval_CallFunction(...);
|
||||
EXPCL_PYSTUB int PyEval_CallObjectWithKeywords(...);
|
||||
EXPCL_PYSTUB int PyEval_InitThreads(...);
|
||||
EXPCL_PYSTUB int PyEval_RestoreThread(...);
|
||||
EXPCL_PYSTUB int PyEval_SaveThread(...);
|
||||
EXPCL_PYSTUB int PyFloat_AsDouble(...);
|
||||
@ -163,6 +163,7 @@ extern "C" {
|
||||
EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
|
||||
EXPCL_PYSTUB int PyUnicode_AsWideChar(...);
|
||||
EXPCL_PYSTUB int PyUnicode_AsWideCharString(...);
|
||||
EXPCL_PYSTUB int PyUnicode_CompareWithASCIIString(...);
|
||||
EXPCL_PYSTUB int PyUnicode_FromFormat(...);
|
||||
EXPCL_PYSTUB int PyUnicode_FromString(...);
|
||||
EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
|
||||
@ -180,12 +181,16 @@ extern "C" {
|
||||
EXPCL_PYSTUB int _PyArg_ParseTuple_SizeT(...);
|
||||
EXPCL_PYSTUB int _PyArg_ParseTupleAndKeywords_SizeT(...);
|
||||
EXPCL_PYSTUB int _PyArg_Parse_SizeT(...);
|
||||
EXPCL_PYSTUB int _PyErr_BadInternalCall(...);
|
||||
EXPCL_PYSTUB int _PyLong_AsByteArray(...);
|
||||
EXPCL_PYSTUB int _PyObject_CallFunction_SizeT(...);
|
||||
EXPCL_PYSTUB int _PyObject_CallMethod_SizeT(...);
|
||||
EXPCL_PYSTUB int _PyObject_DebugFree(...);
|
||||
EXPCL_PYSTUB int _PyObject_Del(...);
|
||||
EXPCL_PYSTUB int _PyObject_FastCallDict(...);
|
||||
EXPCL_PYSTUB int _PyUnicode_AsString(...);
|
||||
EXPCL_PYSTUB int _PyUnicode_AsStringAndSize(...);
|
||||
EXPCL_PYSTUB int _PyUnicode_EqualToASCIIString(...);
|
||||
EXPCL_PYSTUB int _Py_AddToAllObjects(...);
|
||||
EXPCL_PYSTUB int _Py_BuildValue_SizeT(...);
|
||||
EXPCL_PYSTUB int _Py_Dealloc(...);
|
||||
@ -198,6 +203,7 @@ extern "C" {
|
||||
|
||||
EXPCL_PYSTUB void Py_Initialize();
|
||||
EXPCL_PYSTUB int Py_IsInitialized();
|
||||
EXPCL_PYSTUB void PyEval_InitThreads();
|
||||
|
||||
EXPCL_PYSTUB extern void *PyExc_AssertionError;
|
||||
EXPCL_PYSTUB extern void *PyExc_AttributeError;
|
||||
@ -208,6 +214,7 @@ extern "C" {
|
||||
EXPCL_PYSTUB extern void *PyExc_ImportError;
|
||||
EXPCL_PYSTUB extern void *PyExc_IndexError;
|
||||
EXPCL_PYSTUB extern void *PyExc_OSError;
|
||||
EXPCL_PYSTUB extern void *PyExc_OverflowError;
|
||||
EXPCL_PYSTUB extern void *PyExc_RuntimeError;
|
||||
EXPCL_PYSTUB extern void *PyExc_StandardError;
|
||||
EXPCL_PYSTUB extern void *PyExc_StopIteration;
|
||||
@ -241,6 +248,7 @@ int PyDict_DelItemString(...) { return 0; }
|
||||
int PyDict_GetItem(...) { return 0; }
|
||||
int PyDict_GetItemString(...) { return 0; }
|
||||
int PyDict_New(...) { return 0; };
|
||||
int PyDict_Next(...) { return 0; };
|
||||
int PyDict_SetItem(...) { return 0; };
|
||||
int PyDict_SetItemString(...) { return 0; };
|
||||
int PyDict_Size(...){ return 0; }
|
||||
@ -372,6 +380,7 @@ int PyUnicode_AsUTF8(...) { return 0; }
|
||||
int PyUnicode_AsUTF8AndSize(...) { return 0; }
|
||||
int PyUnicode_AsWideChar(...) { return 0; }
|
||||
int PyUnicode_AsWideCharString(...) { return 0; }
|
||||
int PyUnicode_CompareWithASCIIString(...) { return 0; }
|
||||
int PyUnicode_FromFormat(...) { return 0; }
|
||||
int PyUnicode_FromString(...) { return 0; }
|
||||
int PyUnicode_FromStringAndSize(...) { return 0; }
|
||||
@ -389,12 +398,16 @@ int Py_InitModule4TraceRefs_64(...) { return 0; };
|
||||
int _PyArg_ParseTuple_SizeT(...) { return 0; };
|
||||
int _PyArg_ParseTupleAndKeywords_SizeT(...) { return 0; };
|
||||
int _PyArg_Parse_SizeT(...) { return 0; };
|
||||
int _PyErr_BadInternalCall(...) { return 0; };
|
||||
int _PyLong_AsByteArray(...) { return 0; };
|
||||
int _PyObject_CallFunction_SizeT(...) { return 0; };
|
||||
int _PyObject_CallMethod_SizeT(...) { return 0; };
|
||||
int _PyObject_DebugFree(...) { return 0; };
|
||||
int _PyObject_Del(...) { return 0; };
|
||||
int _PyObject_FastCallDict(...) { return 0; };
|
||||
int _PyUnicode_AsString(...) { return 0; };
|
||||
int _PyUnicode_AsStringAndSize(...) { return 0; };
|
||||
int _PyUnicode_EqualToASCIIString(...) { return 0; };
|
||||
int _Py_AddToAllObjects(...) { return 0; };
|
||||
int _Py_BuildValue_SizeT(...) { return 0; };
|
||||
int _Py_Dealloc(...) { return 0; };
|
||||
@ -411,6 +424,8 @@ void Py_Initialize() {
|
||||
int Py_IsInitialized() {
|
||||
return 0;
|
||||
}
|
||||
void PyEval_InitThreads() {
|
||||
}
|
||||
|
||||
|
||||
void *PyExc_AssertionError = (void *)NULL;
|
||||
@ -422,6 +437,7 @@ void *PyExc_FutureWarning = (void *)NULL;
|
||||
void *PyExc_ImportError = (void *)NULL;
|
||||
void *PyExc_IndexError = (void *)NULL;
|
||||
void *PyExc_OSError = (void *)NULL;
|
||||
void *PyExc_OverflowError = (void *)NULL;
|
||||
void *PyExc_RuntimeError = (void *)NULL;
|
||||
void *PyExc_StandardError = (void *)NULL;
|
||||
void *PyExc_StopIteration = (void *)NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user