init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
450
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargs.c
Normal file
450
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargs.c
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
/* getargs implementation copied from Python 3.8 and stripped down to only include
|
||||
* the functions we need.
|
||||
* We also add support for required kwonly args and accepting *args / **kwargs.
|
||||
* A good idea would be to also vendor in the Fast versions and get our stuff
|
||||
* working with *that*.
|
||||
* Another probably good idea is to strip out all the formatting stuff we don't need
|
||||
* and then add in custom stuff that we do need.
|
||||
*
|
||||
* DOCUMENTATION OF THE EXTENSIONS:
|
||||
* - Arguments given after a @ format specify are required keyword-only arguments.
|
||||
* The | and $ specifiers must both appear before @.
|
||||
* - If the first character of a format string is %, then the function can support
|
||||
* *args and **kwargs. On seeing a %, the parser will consume two arguments,
|
||||
* which should be pointers to variables to store the *args and **kwargs, respectively.
|
||||
* Either pointer can be NULL, in which case the function doesn't take that
|
||||
* variety of vararg.
|
||||
* Unlike most format specifiers, the caller takes ownership of these objects
|
||||
* and is responsible for decrefing them.
|
||||
* - All arguments must use the 'O' format.
|
||||
* - There's minimal error checking of format strings. They are generated
|
||||
* programmatically and can be assumed valid.
|
||||
*/
|
||||
|
||||
// These macro definitions are copied from pyport.h in Python 3.9 and later
|
||||
// https://bugs.python.org/issue19569
|
||||
#if defined(__clang__)
|
||||
#define _Py_COMP_DIAG_PUSH _Pragma("clang diagnostic push")
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define _Py_COMP_DIAG_POP _Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__) \
|
||||
&& ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
|
||||
#define _Py_COMP_DIAG_PUSH _Pragma("GCC diagnostic push")
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define _Py_COMP_DIAG_POP _Pragma("GCC diagnostic pop")
|
||||
#elif defined(_MSC_VER)
|
||||
#define _Py_COMP_DIAG_PUSH __pragma(warning(push))
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS __pragma(warning(disable: 4996))
|
||||
#define _Py_COMP_DIAG_POP __pragma(warning(pop))
|
||||
#else
|
||||
#define _Py_COMP_DIAG_PUSH
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS
|
||||
#define _Py_COMP_DIAG_POP
|
||||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
#include "pythonsupport.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifndef PyDict_GET_SIZE
|
||||
#define PyDict_GET_SIZE(d) PyDict_Size(d)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int CPyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
|
||||
const char *, const char *, const char * const *, ...);
|
||||
|
||||
/* Forward */
|
||||
static int vgetargskeywords(PyObject *, PyObject *,
|
||||
const char *, const char *, const char * const *, va_list *);
|
||||
static void skipitem(const char **, va_list *);
|
||||
|
||||
/* Support for keyword arguments donated by
|
||||
Geoff Philbrick <philbric@delphi.hks.com> */
|
||||
|
||||
/* Return false (0) for error, else true. */
|
||||
int
|
||||
CPyArg_ParseTupleAndKeywords(PyObject *args,
|
||||
PyObject *keywords,
|
||||
const char *format,
|
||||
const char *fname,
|
||||
const char * const *kwlist, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, kwlist);
|
||||
retval = vgetargskeywords(args, keywords, format, fname, kwlist, &va);
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
|
||||
|
||||
static int
|
||||
vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
|
||||
const char *fname, const char * const *kwlist, va_list *p_va)
|
||||
{
|
||||
int min = INT_MAX;
|
||||
int max = INT_MAX;
|
||||
int required_kwonly_start = INT_MAX;
|
||||
int has_required_kws = 0;
|
||||
int i, pos, len;
|
||||
int skip = 0;
|
||||
Py_ssize_t nargs, nkwargs;
|
||||
PyObject *current_arg;
|
||||
int bound_pos_args;
|
||||
|
||||
PyObject **p_args = NULL, **p_kwargs = NULL;
|
||||
|
||||
assert(args != NULL && PyTuple_Check(args));
|
||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||
assert(format != NULL);
|
||||
assert(kwlist != NULL);
|
||||
assert(p_va != NULL);
|
||||
|
||||
/* scan kwlist and count the number of positional-only parameters */
|
||||
for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) {
|
||||
}
|
||||
/* scan kwlist and get greatest possible nbr of args */
|
||||
for (len = pos; kwlist[len]; len++) {
|
||||
#ifdef DEBUG
|
||||
if (!*kwlist[len]) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty keyword parameter name");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*format == '%') {
|
||||
p_args = va_arg(*p_va, PyObject **);
|
||||
p_kwargs = va_arg(*p_va, PyObject **);
|
||||
format++;
|
||||
}
|
||||
|
||||
nargs = PyTuple_GET_SIZE(args);
|
||||
nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
|
||||
if (unlikely(nargs + nkwargs > len && !p_args && !p_kwargs)) {
|
||||
/* Adding "keyword" (when nargs == 0) prevents producing wrong error
|
||||
messages in some special cases (see bpo-31229). */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes at most %d %sargument%s (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
len,
|
||||
(nargs == 0) ? "keyword " : "",
|
||||
(len == 1) ? "" : "s",
|
||||
nargs + nkwargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert tuple args and keyword args in same loop, using kwlist to drive process */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (*format == '|') {
|
||||
#ifdef DEBUG
|
||||
if (min != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (| specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
min = i;
|
||||
format++;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ before |)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there are optional args, figure out whether we have
|
||||
* required keyword arguments so that we don't bail without
|
||||
* enforcing them. */
|
||||
has_required_kws = strchr(format, '@') != NULL;
|
||||
}
|
||||
if (*format == '$') {
|
||||
#ifdef DEBUG
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
max = i;
|
||||
format++;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (max < pos) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty parameter name after $");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (skip) {
|
||||
/* Now we know the minimal and the maximal numbers of
|
||||
* positional arguments and can raise an exception with
|
||||
* informative message (see below). */
|
||||
break;
|
||||
}
|
||||
if (unlikely(max < nargs && !p_args)) {
|
||||
if (max == 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s"
|
||||
" (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
(min < max) ? "at most" : "exactly",
|
||||
max,
|
||||
max == 1 ? "" : "s",
|
||||
nargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (*format == '@') {
|
||||
#ifdef DEBUG
|
||||
if (min == INT_MAX && max == INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string "
|
||||
"(@ without preceding | and $)");
|
||||
return 0;
|
||||
}
|
||||
if (required_kwonly_start != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (@ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
required_kwonly_start = i;
|
||||
format++;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (IS_END_OF_FORMAT(*format)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"More keyword list entries (%d) than "
|
||||
"format specifiers (%d)", len, i);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (!skip) {
|
||||
if (i < nargs && i < max) {
|
||||
current_arg = PyTuple_GET_ITEM(args, i);
|
||||
}
|
||||
else if (nkwargs && i >= pos) {
|
||||
current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
|
||||
if (current_arg) {
|
||||
--nkwargs;
|
||||
}
|
||||
else if (PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_arg = NULL;
|
||||
}
|
||||
|
||||
if (current_arg) {
|
||||
PyObject **p = va_arg(*p_va, PyObject **);
|
||||
*p = current_arg;
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < min || i >= required_kwonly_start) {
|
||||
if (likely(i < pos)) {
|
||||
assert (min == INT_MAX);
|
||||
assert (max == INT_MAX);
|
||||
skip = 1;
|
||||
/* At that moment we still don't know the minimal and
|
||||
* the maximal numbers of positional arguments. Raising
|
||||
* an exception is deferred until we encounter | and $
|
||||
* or the end of the format. */
|
||||
}
|
||||
else {
|
||||
if (i >= max) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s missing required "
|
||||
"keyword-only argument '%s'",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i]);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s missing required "
|
||||
"argument '%s' (pos %d)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i], i+1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* current code reports success when all required args
|
||||
* fulfilled and no keyword args left, with no further
|
||||
* validation. XXX Maybe skip this in debug build ?
|
||||
*/
|
||||
if (!nkwargs && !skip && !has_required_kws &&
|
||||
!p_args && !p_kwargs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are into optional args, skip through to any remaining
|
||||
* keyword args */
|
||||
skipitem(&format, p_va);
|
||||
}
|
||||
|
||||
if (unlikely(skip)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s"
|
||||
" (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
(Py_MIN(pos, min) < i) ? "at least" : "exactly",
|
||||
Py_MIN(pos, min),
|
||||
Py_MIN(pos, min) == 1 ? "" : "s",
|
||||
nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!IS_END_OF_FORMAT(*format) &&
|
||||
(*format != '|') && (*format != '$') && (*format != '@'))
|
||||
{
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"more argument specifiers than keyword list entries "
|
||||
"(remaining format:'%s')", format);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bound_pos_args = Py_MIN(nargs, Py_MIN(max, len));
|
||||
if (p_args) {
|
||||
*p_args = PyTuple_GetSlice(args, bound_pos_args, nargs);
|
||||
if (!*p_args) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_kwargs) {
|
||||
/* This unfortunately needs to be special cased because if len is 0 then we
|
||||
* never go through the main loop. */
|
||||
if (unlikely(nargs > 0 && len == 0 && !p_args)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*p_kwargs = PyDict_New();
|
||||
if (!*p_kwargs) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
|
||||
if (nkwargs > 0) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t j;
|
||||
/* make sure there are no arguments given by name and position */
|
||||
for (i = pos; i < bound_pos_args && i < len; i++) {
|
||||
current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
|
||||
if (unlikely(current_arg != NULL)) {
|
||||
/* arg present in tuple and in dict */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"argument for %.200s%s given by name ('%s') "
|
||||
"and position (%d)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i], i+1);
|
||||
goto latefail;
|
||||
}
|
||||
else if (unlikely(PyErr_Occurred() != NULL)) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
/* make sure there are no extraneous keyword arguments */
|
||||
j = 0;
|
||||
while (PyDict_Next(kwargs, &j, &key, &value)) {
|
||||
int match = 0;
|
||||
if (unlikely(!PyUnicode_Check(key))) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"keywords must be strings");
|
||||
goto latefail;
|
||||
}
|
||||
for (i = pos; i < len; i++) {
|
||||
if (CPyUnicode_EqualToASCIIString(key, kwlist[i])) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
if (unlikely(!p_kwargs)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%U' is an invalid keyword "
|
||||
"argument for %.200s%s",
|
||||
key,
|
||||
(fname == NULL) ? "this function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
goto latefail;
|
||||
} else {
|
||||
if (PyDict_SetItem(*p_kwargs, key, value) < 0) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Handle failures that have happened after we have tried to
|
||||
* create *args and **kwargs, if they exist. */
|
||||
latefail:
|
||||
if (p_args) {
|
||||
Py_XDECREF(*p_args);
|
||||
}
|
||||
if (p_kwargs) {
|
||||
Py_XDECREF(*p_kwargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
skipitem(const char **p_format, va_list *p_va)
|
||||
{
|
||||
const char *format = *p_format;
|
||||
char c = *format++;
|
||||
|
||||
if (p_va != NULL) {
|
||||
(void) va_arg(*p_va, PyObject **);
|
||||
}
|
||||
|
||||
*p_format = format;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue