aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python/src/Python
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-09-29 12:24:06 +0300
committernkozlovskiy <nmk@ydb.tech>2023-09-29 12:41:34 +0300
commite0e3e1717e3d33762ce61950504f9637a6e669ed (patch)
treebca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python/src/Python
parent38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff)
downloadydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz
add ydb deps
Diffstat (limited to 'contrib/tools/python/src/Python')
-rw-r--r--contrib/tools/python/src/Python/Python-ast.c6968
-rw-r--r--contrib/tools/python/src/Python/_warnings.c917
-rw-r--r--contrib/tools/python/src/Python/asdl.c64
-rw-r--r--contrib/tools/python/src/Python/ast.c3589
-rw-r--r--contrib/tools/python/src/Python/bltinmodule.c3081
-rw-r--r--contrib/tools/python/src/Python/ceval.c5278
-rw-r--r--contrib/tools/python/src/Python/codecs.c1045
-rw-r--r--contrib/tools/python/src/Python/compile.c3976
-rw-r--r--contrib/tools/python/src/Python/dtoa.c2949
-rw-r--r--contrib/tools/python/src/Python/dynload_shlib.c143
-rw-r--r--contrib/tools/python/src/Python/dynload_win.c280
-rw-r--r--contrib/tools/python/src/Python/errors.c830
-rw-r--r--contrib/tools/python/src/Python/formatter_string.c17
-rw-r--r--contrib/tools/python/src/Python/formatter_unicode.c18
-rw-r--r--contrib/tools/python/src/Python/frozen.c38
-rw-r--r--contrib/tools/python/src/Python/future.c137
-rw-r--r--contrib/tools/python/src/Python/getargs.c1934
-rw-r--r--contrib/tools/python/src/Python/getcompiler.c28
-rw-r--r--contrib/tools/python/src/Python/getcopyright.c23
-rw-r--r--contrib/tools/python/src/Python/getopt.c136
-rw-r--r--contrib/tools/python/src/Python/getplatform.c12
-rw-r--r--contrib/tools/python/src/Python/getversion.c15
-rw-r--r--contrib/tools/python/src/Python/graminit.c2177
-rw-r--r--contrib/tools/python/src/Python/import.c3533
-rw-r--r--contrib/tools/python/src/Python/importdl.c78
-rw-r--r--contrib/tools/python/src/Python/importdl.h53
-rw-r--r--contrib/tools/python/src/Python/marshal.c1423
-rw-r--r--contrib/tools/python/src/Python/modsupport.c670
-rw-r--r--contrib/tools/python/src/Python/mysnprintf.c105
-rw-r--r--contrib/tools/python/src/Python/mystrtoul.c285
-rw-r--r--contrib/tools/python/src/Python/opcode_targets.h258
-rw-r--r--contrib/tools/python/src/Python/peephole.c674
-rw-r--r--contrib/tools/python/src/Python/pyarena.c213
-rw-r--r--contrib/tools/python/src/Python/pyctype.c214
-rw-r--r--contrib/tools/python/src/Python/pyfpe.c23
-rw-r--r--contrib/tools/python/src/Python/pymath.c79
-rw-r--r--contrib/tools/python/src/Python/pystate.c681
-rw-r--r--contrib/tools/python/src/Python/pystrcmp.c26
-rw-r--r--contrib/tools/python/src/Python/pystrtod.c1247
-rw-r--r--contrib/tools/python/src/Python/pythonrun.c2088
-rw-r--r--contrib/tools/python/src/Python/random.c435
-rw-r--r--contrib/tools/python/src/Python/structmember.c363
-rw-r--r--contrib/tools/python/src/Python/symtable.c1612
-rw-r--r--contrib/tools/python/src/Python/sysmodule.c1800
-rw-r--r--contrib/tools/python/src/Python/thread.c421
-rw-r--r--contrib/tools/python/src/Python/thread_atheos.h259
-rw-r--r--contrib/tools/python/src/Python/thread_beos.h248
-rw-r--r--contrib/tools/python/src/Python/thread_cthread.h112
-rw-r--r--contrib/tools/python/src/Python/thread_lwp.h113
-rw-r--r--contrib/tools/python/src/Python/thread_nt.h359
-rw-r--r--contrib/tools/python/src/Python/thread_os2.h267
-rw-r--r--contrib/tools/python/src/Python/thread_pth.h178
-rw-r--r--contrib/tools/python/src/Python/thread_pthread.h553
-rw-r--r--contrib/tools/python/src/Python/thread_sgi.h259
-rw-r--r--contrib/tools/python/src/Python/traceback.c279
55 files changed, 52563 insertions, 0 deletions
diff --git a/contrib/tools/python/src/Python/Python-ast.c b/contrib/tools/python/src/Python/Python-ast.c
new file mode 100644
index 0000000000..2e7a1afbbc
--- /dev/null
+++ b/contrib/tools/python/src/Python/Python-ast.c
@@ -0,0 +1,6968 @@
+/* File automatically generated by Parser/asdl_c.py. */
+
+
+/*
+ __version__ 82160.
+
+ This module must be committed separately after each AST grammar change;
+ The __version__ number is set to the revision number of the commit
+ containing the grammar change.
+*/
+
+#include "Python.h"
+#include "Python-ast.h"
+
+static PyTypeObject AST_type;
+static PyTypeObject *mod_type;
+static PyObject* ast2obj_mod(void*);
+static PyTypeObject *Module_type;
+static char *Module_fields[]={
+ "body",
+};
+static PyTypeObject *Interactive_type;
+static char *Interactive_fields[]={
+ "body",
+};
+static PyTypeObject *Expression_type;
+static char *Expression_fields[]={
+ "body",
+};
+static PyTypeObject *Suite_type;
+static char *Suite_fields[]={
+ "body",
+};
+static PyTypeObject *stmt_type;
+static char *stmt_attributes[] = {
+ "lineno",
+ "col_offset",
+};
+static PyObject* ast2obj_stmt(void*);
+static PyTypeObject *FunctionDef_type;
+static char *FunctionDef_fields[]={
+ "name",
+ "args",
+ "body",
+ "decorator_list",
+};
+static PyTypeObject *ClassDef_type;
+static char *ClassDef_fields[]={
+ "name",
+ "bases",
+ "body",
+ "decorator_list",
+};
+static PyTypeObject *Return_type;
+static char *Return_fields[]={
+ "value",
+};
+static PyTypeObject *Delete_type;
+static char *Delete_fields[]={
+ "targets",
+};
+static PyTypeObject *Assign_type;
+static char *Assign_fields[]={
+ "targets",
+ "value",
+};
+static PyTypeObject *AugAssign_type;
+static char *AugAssign_fields[]={
+ "target",
+ "op",
+ "value",
+};
+static PyTypeObject *Print_type;
+static char *Print_fields[]={
+ "dest",
+ "values",
+ "nl",
+};
+static PyTypeObject *For_type;
+static char *For_fields[]={
+ "target",
+ "iter",
+ "body",
+ "orelse",
+};
+static PyTypeObject *While_type;
+static char *While_fields[]={
+ "test",
+ "body",
+ "orelse",
+};
+static PyTypeObject *If_type;
+static char *If_fields[]={
+ "test",
+ "body",
+ "orelse",
+};
+static PyTypeObject *With_type;
+static char *With_fields[]={
+ "context_expr",
+ "optional_vars",
+ "body",
+};
+static PyTypeObject *Raise_type;
+static char *Raise_fields[]={
+ "type",
+ "inst",
+ "tback",
+};
+static PyTypeObject *TryExcept_type;
+static char *TryExcept_fields[]={
+ "body",
+ "handlers",
+ "orelse",
+};
+static PyTypeObject *TryFinally_type;
+static char *TryFinally_fields[]={
+ "body",
+ "finalbody",
+};
+static PyTypeObject *Assert_type;
+static char *Assert_fields[]={
+ "test",
+ "msg",
+};
+static PyTypeObject *Import_type;
+static char *Import_fields[]={
+ "names",
+};
+static PyTypeObject *ImportFrom_type;
+static char *ImportFrom_fields[]={
+ "module",
+ "names",
+ "level",
+};
+static PyTypeObject *Exec_type;
+static char *Exec_fields[]={
+ "body",
+ "globals",
+ "locals",
+};
+static PyTypeObject *Global_type;
+static char *Global_fields[]={
+ "names",
+};
+static PyTypeObject *Expr_type;
+static char *Expr_fields[]={
+ "value",
+};
+static PyTypeObject *Pass_type;
+static PyTypeObject *Break_type;
+static PyTypeObject *Continue_type;
+static PyTypeObject *expr_type;
+static char *expr_attributes[] = {
+ "lineno",
+ "col_offset",
+};
+static PyObject* ast2obj_expr(void*);
+static PyTypeObject *BoolOp_type;
+static char *BoolOp_fields[]={
+ "op",
+ "values",
+};
+static PyTypeObject *BinOp_type;
+static char *BinOp_fields[]={
+ "left",
+ "op",
+ "right",
+};
+static PyTypeObject *UnaryOp_type;
+static char *UnaryOp_fields[]={
+ "op",
+ "operand",
+};
+static PyTypeObject *Lambda_type;
+static char *Lambda_fields[]={
+ "args",
+ "body",
+};
+static PyTypeObject *IfExp_type;
+static char *IfExp_fields[]={
+ "test",
+ "body",
+ "orelse",
+};
+static PyTypeObject *Dict_type;
+static char *Dict_fields[]={
+ "keys",
+ "values",
+};
+static PyTypeObject *Set_type;
+static char *Set_fields[]={
+ "elts",
+};
+static PyTypeObject *ListComp_type;
+static char *ListComp_fields[]={
+ "elt",
+ "generators",
+};
+static PyTypeObject *SetComp_type;
+static char *SetComp_fields[]={
+ "elt",
+ "generators",
+};
+static PyTypeObject *DictComp_type;
+static char *DictComp_fields[]={
+ "key",
+ "value",
+ "generators",
+};
+static PyTypeObject *GeneratorExp_type;
+static char *GeneratorExp_fields[]={
+ "elt",
+ "generators",
+};
+static PyTypeObject *Yield_type;
+static char *Yield_fields[]={
+ "value",
+};
+static PyTypeObject *Compare_type;
+static char *Compare_fields[]={
+ "left",
+ "ops",
+ "comparators",
+};
+static PyTypeObject *Call_type;
+static char *Call_fields[]={
+ "func",
+ "args",
+ "keywords",
+ "starargs",
+ "kwargs",
+};
+static PyTypeObject *Repr_type;
+static char *Repr_fields[]={
+ "value",
+};
+static PyTypeObject *Num_type;
+static char *Num_fields[]={
+ "n",
+};
+static PyTypeObject *Str_type;
+static char *Str_fields[]={
+ "s",
+};
+static PyTypeObject *Attribute_type;
+static char *Attribute_fields[]={
+ "value",
+ "attr",
+ "ctx",
+};
+static PyTypeObject *Subscript_type;
+static char *Subscript_fields[]={
+ "value",
+ "slice",
+ "ctx",
+};
+static PyTypeObject *Name_type;
+static char *Name_fields[]={
+ "id",
+ "ctx",
+};
+static PyTypeObject *List_type;
+static char *List_fields[]={
+ "elts",
+ "ctx",
+};
+static PyTypeObject *Tuple_type;
+static char *Tuple_fields[]={
+ "elts",
+ "ctx",
+};
+static PyTypeObject *expr_context_type;
+static PyObject *Load_singleton, *Store_singleton, *Del_singleton,
+*AugLoad_singleton, *AugStore_singleton, *Param_singleton;
+static PyObject* ast2obj_expr_context(expr_context_ty);
+static PyTypeObject *Load_type;
+static PyTypeObject *Store_type;
+static PyTypeObject *Del_type;
+static PyTypeObject *AugLoad_type;
+static PyTypeObject *AugStore_type;
+static PyTypeObject *Param_type;
+static PyTypeObject *slice_type;
+static PyObject* ast2obj_slice(void*);
+static PyTypeObject *Ellipsis_type;
+static PyTypeObject *Slice_type;
+static char *Slice_fields[]={
+ "lower",
+ "upper",
+ "step",
+};
+static PyTypeObject *ExtSlice_type;
+static char *ExtSlice_fields[]={
+ "dims",
+};
+static PyTypeObject *Index_type;
+static char *Index_fields[]={
+ "value",
+};
+static PyTypeObject *boolop_type;
+static PyObject *And_singleton, *Or_singleton;
+static PyObject* ast2obj_boolop(boolop_ty);
+static PyTypeObject *And_type;
+static PyTypeObject *Or_type;
+static PyTypeObject *operator_type;
+static PyObject *Add_singleton, *Sub_singleton, *Mult_singleton,
+*Div_singleton, *Mod_singleton, *Pow_singleton, *LShift_singleton,
+*RShift_singleton, *BitOr_singleton, *BitXor_singleton, *BitAnd_singleton,
+*FloorDiv_singleton;
+static PyObject* ast2obj_operator(operator_ty);
+static PyTypeObject *Add_type;
+static PyTypeObject *Sub_type;
+static PyTypeObject *Mult_type;
+static PyTypeObject *Div_type;
+static PyTypeObject *Mod_type;
+static PyTypeObject *Pow_type;
+static PyTypeObject *LShift_type;
+static PyTypeObject *RShift_type;
+static PyTypeObject *BitOr_type;
+static PyTypeObject *BitXor_type;
+static PyTypeObject *BitAnd_type;
+static PyTypeObject *FloorDiv_type;
+static PyTypeObject *unaryop_type;
+static PyObject *Invert_singleton, *Not_singleton, *UAdd_singleton,
+*USub_singleton;
+static PyObject* ast2obj_unaryop(unaryop_ty);
+static PyTypeObject *Invert_type;
+static PyTypeObject *Not_type;
+static PyTypeObject *UAdd_type;
+static PyTypeObject *USub_type;
+static PyTypeObject *cmpop_type;
+static PyObject *Eq_singleton, *NotEq_singleton, *Lt_singleton, *LtE_singleton,
+*Gt_singleton, *GtE_singleton, *Is_singleton, *IsNot_singleton, *In_singleton,
+*NotIn_singleton;
+static PyObject* ast2obj_cmpop(cmpop_ty);
+static PyTypeObject *Eq_type;
+static PyTypeObject *NotEq_type;
+static PyTypeObject *Lt_type;
+static PyTypeObject *LtE_type;
+static PyTypeObject *Gt_type;
+static PyTypeObject *GtE_type;
+static PyTypeObject *Is_type;
+static PyTypeObject *IsNot_type;
+static PyTypeObject *In_type;
+static PyTypeObject *NotIn_type;
+static PyTypeObject *comprehension_type;
+static PyObject* ast2obj_comprehension(void*);
+static char *comprehension_fields[]={
+ "target",
+ "iter",
+ "ifs",
+};
+static PyTypeObject *excepthandler_type;
+static char *excepthandler_attributes[] = {
+ "lineno",
+ "col_offset",
+};
+static PyObject* ast2obj_excepthandler(void*);
+static PyTypeObject *ExceptHandler_type;
+static char *ExceptHandler_fields[]={
+ "type",
+ "name",
+ "body",
+};
+static PyTypeObject *arguments_type;
+static PyObject* ast2obj_arguments(void*);
+static char *arguments_fields[]={
+ "args",
+ "vararg",
+ "kwarg",
+ "defaults",
+};
+static PyTypeObject *keyword_type;
+static PyObject* ast2obj_keyword(void*);
+static char *keyword_fields[]={
+ "arg",
+ "value",
+};
+static PyTypeObject *alias_type;
+static PyObject* ast2obj_alias(void*);
+static char *alias_fields[]={
+ "name",
+ "asname",
+};
+
+
+static int
+ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
+{
+ Py_ssize_t i, numfields = 0;
+ int res = -1;
+ PyObject *key, *value, *fields;
+ fields = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "_fields");
+ if (!fields)
+ PyErr_Clear();
+ if (fields) {
+ numfields = PySequence_Size(fields);
+ if (numfields == -1)
+ goto cleanup;
+ }
+ res = 0; /* if no error occurs, this stays 0 to the end */
+ if (PyTuple_GET_SIZE(args) > 0) {
+ if (numfields != PyTuple_GET_SIZE(args)) {
+ PyErr_Format(PyExc_TypeError, "%.400s constructor takes %s"
+ "%zd positional argument%s",
+ Py_TYPE(self)->tp_name,
+ numfields == 0 ? "" : "either 0 or ",
+ numfields, numfields == 1 ? "" : "s");
+ res = -1;
+ goto cleanup;
+ }
+ for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
+ /* cannot be reached when fields is NULL */
+ PyObject *name = PySequence_GetItem(fields, i);
+ if (!name) {
+ res = -1;
+ goto cleanup;
+ }
+ res = PyObject_SetAttr(self, name, PyTuple_GET_ITEM(args, i));
+ Py_DECREF(name);
+ if (res < 0)
+ goto cleanup;
+ }
+ }
+ if (kw) {
+ i = 0; /* needed by PyDict_Next */
+ while (PyDict_Next(kw, &i, &key, &value)) {
+ res = PyObject_SetAttr(self, key, value);
+ if (res < 0)
+ goto cleanup;
+ }
+ }
+ cleanup:
+ Py_XDECREF(fields);
+ return res;
+}
+
+/* Pickling support */
+static PyObject *
+ast_type_reduce(PyObject *self, PyObject *unused)
+{
+ PyObject *res;
+ PyObject *dict = PyObject_GetAttrString(self, "__dict__");
+ if (dict == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_AttributeError))
+ PyErr_Clear();
+ else
+ return NULL;
+ }
+ if (dict) {
+ res = Py_BuildValue("O()O", Py_TYPE(self), dict);
+ Py_DECREF(dict);
+ return res;
+ }
+ return Py_BuildValue("O()", Py_TYPE(self));
+}
+
+static PyMethodDef ast_type_methods[] = {
+ {"__reduce__", ast_type_reduce, METH_NOARGS, NULL},
+ {NULL}
+};
+
+static PyTypeObject AST_type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "_ast.AST",
+ sizeof(PyObject),
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ ast_type_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ast_type_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
+
+static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int num_fields)
+{
+ PyObject *fnames, *result;
+ int i;
+ fnames = PyTuple_New(num_fields);
+ if (!fnames) return NULL;
+ for (i = 0; i < num_fields; i++) {
+ PyObject *field = PyString_FromString(fields[i]);
+ if (!field) {
+ Py_DECREF(fnames);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(fnames, i, field);
+ }
+ result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}",
+ type, base, "_fields", fnames, "__module__", "_ast");
+ Py_DECREF(fnames);
+ return (PyTypeObject*)result;
+}
+
+static int add_attributes(PyTypeObject* type, char**attrs, int num_fields)
+{
+ int i, result;
+ PyObject *s, *l = PyTuple_New(num_fields);
+ if (!l)
+ return 0;
+ for (i = 0; i < num_fields; i++) {
+ s = PyString_FromString(attrs[i]);
+ if (!s) {
+ Py_DECREF(l);
+ return 0;
+ }
+ PyTuple_SET_ITEM(l, i, s);
+ }
+ result = PyObject_SetAttrString((PyObject*)type, "_attributes", l) >= 0;
+ Py_DECREF(l);
+ return result;
+}
+
+/* Conversion AST -> Python */
+
+static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*))
+{
+ int i, n = asdl_seq_LEN(seq);
+ PyObject *result = PyList_New(n);
+ PyObject *value;
+ if (!result)
+ return NULL;
+ for (i = 0; i < n; i++) {
+ value = func(asdl_seq_GET(seq, i));
+ if (!value) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ PyList_SET_ITEM(result, i, value);
+ }
+ return result;
+}
+
+static PyObject* ast2obj_object(void *o)
+{
+ if (!o)
+ o = Py_None;
+ Py_INCREF((PyObject*)o);
+ return (PyObject*)o;
+}
+#define ast2obj_identifier ast2obj_object
+#define ast2obj_string ast2obj_object
+static PyObject* ast2obj_bool(bool b)
+{
+ return PyBool_FromLong(b);
+}
+
+static PyObject* ast2obj_int(long b)
+{
+ return PyInt_FromLong(b);
+}
+
+/* Conversion Python -> AST */
+
+static int obj2ast_object(PyObject* obj, PyObject** out, PyArena* arena)
+{
+ if (obj == Py_None)
+ obj = NULL;
+ if (obj)
+ PyArena_AddPyObject(arena, obj);
+ Py_XINCREF(obj);
+ *out = obj;
+ return 0;
+}
+
+static int obj2ast_identifier(PyObject* obj, PyObject** out, PyArena* arena)
+{
+ if (!PyString_CheckExact(obj) && obj != Py_None) {
+ PyErr_Format(PyExc_TypeError,
+ "AST identifier must be of type str");
+ return 1;
+ }
+ return obj2ast_object(obj, out, arena);
+}
+
+static int obj2ast_string(PyObject* obj, PyObject** out, PyArena* arena)
+{
+ if (!PyString_CheckExact(obj) && !PyUnicode_CheckExact(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "AST string must be of type str or unicode");
+ return 1;
+ }
+ return obj2ast_object(obj, out, arena);
+}
+
+static int obj2ast_int(PyObject* obj, int* out, PyArena* arena)
+{
+ int i;
+ if (!_PyAnyInt_Check(obj)) {
+ PyObject *s = PyObject_Repr(obj);
+ if (s == NULL) return 1;
+ PyErr_Format(PyExc_ValueError, "invalid integer value: %.400s",
+ PyString_AS_STRING(s));
+ Py_DECREF(s);
+ return 1;
+ }
+
+ i = (int)PyLong_AsLong(obj);
+ if (i == -1 && PyErr_Occurred())
+ return 1;
+ *out = i;
+ return 0;
+}
+
+static int obj2ast_bool(PyObject* obj, bool* out, PyArena* arena)
+{
+ if (!PyBool_Check(obj)) {
+ PyObject *s = PyObject_Repr(obj);
+ if (s == NULL) return 1;
+ PyErr_Format(PyExc_ValueError, "invalid boolean value: %.400s",
+ PyString_AS_STRING(s));
+ Py_DECREF(s);
+ return 1;
+ }
+
+ *out = (obj == Py_True);
+ return 0;
+}
+
+static int add_ast_fields(void)
+{
+ PyObject *empty_tuple, *d;
+ if (PyType_Ready(&AST_type) < 0)
+ return -1;
+ d = AST_type.tp_dict;
+ empty_tuple = PyTuple_New(0);
+ if (!empty_tuple ||
+ PyDict_SetItemString(d, "_fields", empty_tuple) < 0 ||
+ PyDict_SetItemString(d, "_attributes", empty_tuple) < 0) {
+ Py_XDECREF(empty_tuple);
+ return -1;
+ }
+ Py_DECREF(empty_tuple);
+ return 0;
+}
+
+
+static int init_types(void)
+{
+ static int initialized;
+ if (initialized) return 1;
+ if (add_ast_fields() < 0) return 0;
+ mod_type = make_type("mod", &AST_type, NULL, 0);
+ if (!mod_type) return 0;
+ if (!add_attributes(mod_type, NULL, 0)) return 0;
+ Module_type = make_type("Module", mod_type, Module_fields, 1);
+ if (!Module_type) return 0;
+ Interactive_type = make_type("Interactive", mod_type,
+ Interactive_fields, 1);
+ if (!Interactive_type) return 0;
+ Expression_type = make_type("Expression", mod_type, Expression_fields,
+ 1);
+ if (!Expression_type) return 0;
+ Suite_type = make_type("Suite", mod_type, Suite_fields, 1);
+ if (!Suite_type) return 0;
+ stmt_type = make_type("stmt", &AST_type, NULL, 0);
+ if (!stmt_type) return 0;
+ if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0;
+ FunctionDef_type = make_type("FunctionDef", stmt_type,
+ FunctionDef_fields, 4);
+ if (!FunctionDef_type) return 0;
+ ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 4);
+ if (!ClassDef_type) return 0;
+ Return_type = make_type("Return", stmt_type, Return_fields, 1);
+ if (!Return_type) return 0;
+ Delete_type = make_type("Delete", stmt_type, Delete_fields, 1);
+ if (!Delete_type) return 0;
+ Assign_type = make_type("Assign", stmt_type, Assign_fields, 2);
+ if (!Assign_type) return 0;
+ AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3);
+ if (!AugAssign_type) return 0;
+ Print_type = make_type("Print", stmt_type, Print_fields, 3);
+ if (!Print_type) return 0;
+ For_type = make_type("For", stmt_type, For_fields, 4);
+ if (!For_type) return 0;
+ While_type = make_type("While", stmt_type, While_fields, 3);
+ if (!While_type) return 0;
+ If_type = make_type("If", stmt_type, If_fields, 3);
+ if (!If_type) return 0;
+ With_type = make_type("With", stmt_type, With_fields, 3);
+ if (!With_type) return 0;
+ Raise_type = make_type("Raise", stmt_type, Raise_fields, 3);
+ if (!Raise_type) return 0;
+ TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3);
+ if (!TryExcept_type) return 0;
+ TryFinally_type = make_type("TryFinally", stmt_type, TryFinally_fields,
+ 2);
+ if (!TryFinally_type) return 0;
+ Assert_type = make_type("Assert", stmt_type, Assert_fields, 2);
+ if (!Assert_type) return 0;
+ Import_type = make_type("Import", stmt_type, Import_fields, 1);
+ if (!Import_type) return 0;
+ ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields,
+ 3);
+ if (!ImportFrom_type) return 0;
+ Exec_type = make_type("Exec", stmt_type, Exec_fields, 3);
+ if (!Exec_type) return 0;
+ Global_type = make_type("Global", stmt_type, Global_fields, 1);
+ if (!Global_type) return 0;
+ Expr_type = make_type("Expr", stmt_type, Expr_fields, 1);
+ if (!Expr_type) return 0;
+ Pass_type = make_type("Pass", stmt_type, NULL, 0);
+ if (!Pass_type) return 0;
+ Break_type = make_type("Break", stmt_type, NULL, 0);
+ if (!Break_type) return 0;
+ Continue_type = make_type("Continue", stmt_type, NULL, 0);
+ if (!Continue_type) return 0;
+ expr_type = make_type("expr", &AST_type, NULL, 0);
+ if (!expr_type) return 0;
+ if (!add_attributes(expr_type, expr_attributes, 2)) return 0;
+ BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2);
+ if (!BoolOp_type) return 0;
+ BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3);
+ if (!BinOp_type) return 0;
+ UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2);
+ if (!UnaryOp_type) return 0;
+ Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2);
+ if (!Lambda_type) return 0;
+ IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3);
+ if (!IfExp_type) return 0;
+ Dict_type = make_type("Dict", expr_type, Dict_fields, 2);
+ if (!Dict_type) return 0;
+ Set_type = make_type("Set", expr_type, Set_fields, 1);
+ if (!Set_type) return 0;
+ ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2);
+ if (!ListComp_type) return 0;
+ SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2);
+ if (!SetComp_type) return 0;
+ DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3);
+ if (!DictComp_type) return 0;
+ GeneratorExp_type = make_type("GeneratorExp", expr_type,
+ GeneratorExp_fields, 2);
+ if (!GeneratorExp_type) return 0;
+ Yield_type = make_type("Yield", expr_type, Yield_fields, 1);
+ if (!Yield_type) return 0;
+ Compare_type = make_type("Compare", expr_type, Compare_fields, 3);
+ if (!Compare_type) return 0;
+ Call_type = make_type("Call", expr_type, Call_fields, 5);
+ if (!Call_type) return 0;
+ Repr_type = make_type("Repr", expr_type, Repr_fields, 1);
+ if (!Repr_type) return 0;
+ Num_type = make_type("Num", expr_type, Num_fields, 1);
+ if (!Num_type) return 0;
+ Str_type = make_type("Str", expr_type, Str_fields, 1);
+ if (!Str_type) return 0;
+ Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3);
+ if (!Attribute_type) return 0;
+ Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3);
+ if (!Subscript_type) return 0;
+ Name_type = make_type("Name", expr_type, Name_fields, 2);
+ if (!Name_type) return 0;
+ List_type = make_type("List", expr_type, List_fields, 2);
+ if (!List_type) return 0;
+ Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2);
+ if (!Tuple_type) return 0;
+ expr_context_type = make_type("expr_context", &AST_type, NULL, 0);
+ if (!expr_context_type) return 0;
+ if (!add_attributes(expr_context_type, NULL, 0)) return 0;
+ Load_type = make_type("Load", expr_context_type, NULL, 0);
+ if (!Load_type) return 0;
+ Load_singleton = PyType_GenericNew(Load_type, NULL, NULL);
+ if (!Load_singleton) return 0;
+ Store_type = make_type("Store", expr_context_type, NULL, 0);
+ if (!Store_type) return 0;
+ Store_singleton = PyType_GenericNew(Store_type, NULL, NULL);
+ if (!Store_singleton) return 0;
+ Del_type = make_type("Del", expr_context_type, NULL, 0);
+ if (!Del_type) return 0;
+ Del_singleton = PyType_GenericNew(Del_type, NULL, NULL);
+ if (!Del_singleton) return 0;
+ AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0);
+ if (!AugLoad_type) return 0;
+ AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL);
+ if (!AugLoad_singleton) return 0;
+ AugStore_type = make_type("AugStore", expr_context_type, NULL, 0);
+ if (!AugStore_type) return 0;
+ AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL);
+ if (!AugStore_singleton) return 0;
+ Param_type = make_type("Param", expr_context_type, NULL, 0);
+ if (!Param_type) return 0;
+ Param_singleton = PyType_GenericNew(Param_type, NULL, NULL);
+ if (!Param_singleton) return 0;
+ slice_type = make_type("slice", &AST_type, NULL, 0);
+ if (!slice_type) return 0;
+ if (!add_attributes(slice_type, NULL, 0)) return 0;
+ Ellipsis_type = make_type("Ellipsis", slice_type, NULL, 0);
+ if (!Ellipsis_type) return 0;
+ Slice_type = make_type("Slice", slice_type, Slice_fields, 3);
+ if (!Slice_type) return 0;
+ ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1);
+ if (!ExtSlice_type) return 0;
+ Index_type = make_type("Index", slice_type, Index_fields, 1);
+ if (!Index_type) return 0;
+ boolop_type = make_type("boolop", &AST_type, NULL, 0);
+ if (!boolop_type) return 0;
+ if (!add_attributes(boolop_type, NULL, 0)) return 0;
+ And_type = make_type("And", boolop_type, NULL, 0);
+ if (!And_type) return 0;
+ And_singleton = PyType_GenericNew(And_type, NULL, NULL);
+ if (!And_singleton) return 0;
+ Or_type = make_type("Or", boolop_type, NULL, 0);
+ if (!Or_type) return 0;
+ Or_singleton = PyType_GenericNew(Or_type, NULL, NULL);
+ if (!Or_singleton) return 0;
+ operator_type = make_type("operator", &AST_type, NULL, 0);
+ if (!operator_type) return 0;
+ if (!add_attributes(operator_type, NULL, 0)) return 0;
+ Add_type = make_type("Add", operator_type, NULL, 0);
+ if (!Add_type) return 0;
+ Add_singleton = PyType_GenericNew(Add_type, NULL, NULL);
+ if (!Add_singleton) return 0;
+ Sub_type = make_type("Sub", operator_type, NULL, 0);
+ if (!Sub_type) return 0;
+ Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL);
+ if (!Sub_singleton) return 0;
+ Mult_type = make_type("Mult", operator_type, NULL, 0);
+ if (!Mult_type) return 0;
+ Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL);
+ if (!Mult_singleton) return 0;
+ Div_type = make_type("Div", operator_type, NULL, 0);
+ if (!Div_type) return 0;
+ Div_singleton = PyType_GenericNew(Div_type, NULL, NULL);
+ if (!Div_singleton) return 0;
+ Mod_type = make_type("Mod", operator_type, NULL, 0);
+ if (!Mod_type) return 0;
+ Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL);
+ if (!Mod_singleton) return 0;
+ Pow_type = make_type("Pow", operator_type, NULL, 0);
+ if (!Pow_type) return 0;
+ Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL);
+ if (!Pow_singleton) return 0;
+ LShift_type = make_type("LShift", operator_type, NULL, 0);
+ if (!LShift_type) return 0;
+ LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL);
+ if (!LShift_singleton) return 0;
+ RShift_type = make_type("RShift", operator_type, NULL, 0);
+ if (!RShift_type) return 0;
+ RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL);
+ if (!RShift_singleton) return 0;
+ BitOr_type = make_type("BitOr", operator_type, NULL, 0);
+ if (!BitOr_type) return 0;
+ BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL);
+ if (!BitOr_singleton) return 0;
+ BitXor_type = make_type("BitXor", operator_type, NULL, 0);
+ if (!BitXor_type) return 0;
+ BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL);
+ if (!BitXor_singleton) return 0;
+ BitAnd_type = make_type("BitAnd", operator_type, NULL, 0);
+ if (!BitAnd_type) return 0;
+ BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL);
+ if (!BitAnd_singleton) return 0;
+ FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0);
+ if (!FloorDiv_type) return 0;
+ FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL);
+ if (!FloorDiv_singleton) return 0;
+ unaryop_type = make_type("unaryop", &AST_type, NULL, 0);
+ if (!unaryop_type) return 0;
+ if (!add_attributes(unaryop_type, NULL, 0)) return 0;
+ Invert_type = make_type("Invert", unaryop_type, NULL, 0);
+ if (!Invert_type) return 0;
+ Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL);
+ if (!Invert_singleton) return 0;
+ Not_type = make_type("Not", unaryop_type, NULL, 0);
+ if (!Not_type) return 0;
+ Not_singleton = PyType_GenericNew(Not_type, NULL, NULL);
+ if (!Not_singleton) return 0;
+ UAdd_type = make_type("UAdd", unaryop_type, NULL, 0);
+ if (!UAdd_type) return 0;
+ UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL);
+ if (!UAdd_singleton) return 0;
+ USub_type = make_type("USub", unaryop_type, NULL, 0);
+ if (!USub_type) return 0;
+ USub_singleton = PyType_GenericNew(USub_type, NULL, NULL);
+ if (!USub_singleton) return 0;
+ cmpop_type = make_type("cmpop", &AST_type, NULL, 0);
+ if (!cmpop_type) return 0;
+ if (!add_attributes(cmpop_type, NULL, 0)) return 0;
+ Eq_type = make_type("Eq", cmpop_type, NULL, 0);
+ if (!Eq_type) return 0;
+ Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL);
+ if (!Eq_singleton) return 0;
+ NotEq_type = make_type("NotEq", cmpop_type, NULL, 0);
+ if (!NotEq_type) return 0;
+ NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL);
+ if (!NotEq_singleton) return 0;
+ Lt_type = make_type("Lt", cmpop_type, NULL, 0);
+ if (!Lt_type) return 0;
+ Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL);
+ if (!Lt_singleton) return 0;
+ LtE_type = make_type("LtE", cmpop_type, NULL, 0);
+ if (!LtE_type) return 0;
+ LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL);
+ if (!LtE_singleton) return 0;
+ Gt_type = make_type("Gt", cmpop_type, NULL, 0);
+ if (!Gt_type) return 0;
+ Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL);
+ if (!Gt_singleton) return 0;
+ GtE_type = make_type("GtE", cmpop_type, NULL, 0);
+ if (!GtE_type) return 0;
+ GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL);
+ if (!GtE_singleton) return 0;
+ Is_type = make_type("Is", cmpop_type, NULL, 0);
+ if (!Is_type) return 0;
+ Is_singleton = PyType_GenericNew(Is_type, NULL, NULL);
+ if (!Is_singleton) return 0;
+ IsNot_type = make_type("IsNot", cmpop_type, NULL, 0);
+ if (!IsNot_type) return 0;
+ IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL);
+ if (!IsNot_singleton) return 0;
+ In_type = make_type("In", cmpop_type, NULL, 0);
+ if (!In_type) return 0;
+ In_singleton = PyType_GenericNew(In_type, NULL, NULL);
+ if (!In_singleton) return 0;
+ NotIn_type = make_type("NotIn", cmpop_type, NULL, 0);
+ if (!NotIn_type) return 0;
+ NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL);
+ if (!NotIn_singleton) return 0;
+ comprehension_type = make_type("comprehension", &AST_type,
+ comprehension_fields, 3);
+ if (!comprehension_type) return 0;
+ excepthandler_type = make_type("excepthandler", &AST_type, NULL, 0);
+ if (!excepthandler_type) return 0;
+ if (!add_attributes(excepthandler_type, excepthandler_attributes, 2))
+ return 0;
+ ExceptHandler_type = make_type("ExceptHandler", excepthandler_type,
+ ExceptHandler_fields, 3);
+ if (!ExceptHandler_type) return 0;
+ arguments_type = make_type("arguments", &AST_type, arguments_fields, 4);
+ if (!arguments_type) return 0;
+ keyword_type = make_type("keyword", &AST_type, keyword_fields, 2);
+ if (!keyword_type) return 0;
+ alias_type = make_type("alias", &AST_type, alias_fields, 2);
+ if (!alias_type) return 0;
+ initialized = 1;
+ return 1;
+}
+
+static int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena);
+static int obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena);
+static int obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena);
+static int obj2ast_expr_context(PyObject* obj, expr_context_ty* out, PyArena*
+ arena);
+static int obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena);
+static int obj2ast_boolop(PyObject* obj, boolop_ty* out, PyArena* arena);
+static int obj2ast_operator(PyObject* obj, operator_ty* out, PyArena* arena);
+static int obj2ast_unaryop(PyObject* obj, unaryop_ty* out, PyArena* arena);
+static int obj2ast_cmpop(PyObject* obj, cmpop_ty* out, PyArena* arena);
+static int obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena*
+ arena);
+static int obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena*
+ arena);
+static int obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena);
+static int obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena);
+static int obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena);
+
+mod_ty
+Module(asdl_seq * body, PyArena *arena)
+{
+ mod_ty p;
+ p = (mod_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Module_kind;
+ p->v.Module.body = body;
+ return p;
+}
+
+mod_ty
+Interactive(asdl_seq * body, PyArena *arena)
+{
+ mod_ty p;
+ p = (mod_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Interactive_kind;
+ p->v.Interactive.body = body;
+ return p;
+}
+
+mod_ty
+Expression(expr_ty body, PyArena *arena)
+{
+ mod_ty p;
+ if (!body) {
+ PyErr_SetString(PyExc_ValueError,
+ "field body is required for Expression");
+ return NULL;
+ }
+ p = (mod_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Expression_kind;
+ p->v.Expression.body = body;
+ return p;
+}
+
+mod_ty
+Suite(asdl_seq * body, PyArena *arena)
+{
+ mod_ty p;
+ p = (mod_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Suite_kind;
+ p->v.Suite.body = body;
+ return p;
+}
+
+stmt_ty
+FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq *
+ decorator_list, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!name) {
+ PyErr_SetString(PyExc_ValueError,
+ "field name is required for FunctionDef");
+ return NULL;
+ }
+ if (!args) {
+ PyErr_SetString(PyExc_ValueError,
+ "field args is required for FunctionDef");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = FunctionDef_kind;
+ p->v.FunctionDef.name = name;
+ p->v.FunctionDef.args = args;
+ p->v.FunctionDef.body = body;
+ p->v.FunctionDef.decorator_list = decorator_list;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, asdl_seq *
+ decorator_list, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!name) {
+ PyErr_SetString(PyExc_ValueError,
+ "field name is required for ClassDef");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = ClassDef_kind;
+ p->v.ClassDef.name = name;
+ p->v.ClassDef.bases = bases;
+ p->v.ClassDef.body = body;
+ p->v.ClassDef.decorator_list = decorator_list;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Return(expr_ty value, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Return_kind;
+ p->v.Return.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Delete(asdl_seq * targets, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Delete_kind;
+ p->v.Delete.targets = targets;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Assign(asdl_seq * targets, expr_ty value, int lineno, int col_offset, PyArena
+ *arena)
+{
+ stmt_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Assign");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Assign_kind;
+ p->v.Assign.targets = targets;
+ p->v.Assign.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int
+ col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!target) {
+ PyErr_SetString(PyExc_ValueError,
+ "field target is required for AugAssign");
+ return NULL;
+ }
+ if (!op) {
+ PyErr_SetString(PyExc_ValueError,
+ "field op is required for AugAssign");
+ return NULL;
+ }
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for AugAssign");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = AugAssign_kind;
+ p->v.AugAssign.target = target;
+ p->v.AugAssign.op = op;
+ p->v.AugAssign.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Print(expr_ty dest, asdl_seq * values, bool nl, int lineno, int col_offset,
+ PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Print_kind;
+ p->v.Print.dest = dest;
+ p->v.Print.values = values;
+ p->v.Print.nl = nl;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int
+ lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!target) {
+ PyErr_SetString(PyExc_ValueError,
+ "field target is required for For");
+ return NULL;
+ }
+ if (!iter) {
+ PyErr_SetString(PyExc_ValueError,
+ "field iter is required for For");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = For_kind;
+ p->v.For.target = target;
+ p->v.For.iter = iter;
+ p->v.For.body = body;
+ p->v.For.orelse = orelse;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int
+ col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!test) {
+ PyErr_SetString(PyExc_ValueError,
+ "field test is required for While");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = While_kind;
+ p->v.While.test = test;
+ p->v.While.body = body;
+ p->v.While.orelse = orelse;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int
+ col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!test) {
+ PyErr_SetString(PyExc_ValueError,
+ "field test is required for If");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = If_kind;
+ p->v.If.test = test;
+ p->v.If.body = body;
+ p->v.If.orelse = orelse;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno,
+ int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!context_expr) {
+ PyErr_SetString(PyExc_ValueError,
+ "field context_expr is required for With");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = With_kind;
+ p->v.With.context_expr = context_expr;
+ p->v.With.optional_vars = optional_vars;
+ p->v.With.body = body;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int col_offset,
+ PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Raise_kind;
+ p->v.Raise.type = type;
+ p->v.Raise.inst = inst;
+ p->v.Raise.tback = tback;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int lineno,
+ int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = TryExcept_kind;
+ p->v.TryExcept.body = body;
+ p->v.TryExcept.handlers = handlers;
+ p->v.TryExcept.orelse = orelse;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno, int col_offset,
+ PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = TryFinally_kind;
+ p->v.TryFinally.body = body;
+ p->v.TryFinally.finalbody = finalbody;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!test) {
+ PyErr_SetString(PyExc_ValueError,
+ "field test is required for Assert");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Assert_kind;
+ p->v.Assert.test = test;
+ p->v.Assert.msg = msg;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Import(asdl_seq * names, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Import_kind;
+ p->v.Import.names = names;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int
+ col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = ImportFrom_kind;
+ p->v.ImportFrom.module = module;
+ p->v.ImportFrom.names = names;
+ p->v.ImportFrom.level = level;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno, int col_offset,
+ PyArena *arena)
+{
+ stmt_ty p;
+ if (!body) {
+ PyErr_SetString(PyExc_ValueError,
+ "field body is required for Exec");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Exec_kind;
+ p->v.Exec.body = body;
+ p->v.Exec.globals = globals;
+ p->v.Exec.locals = locals;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Global(asdl_seq * names, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Global_kind;
+ p->v.Global.names = names;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Expr(expr_ty value, int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Expr");
+ return NULL;
+ }
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Expr_kind;
+ p->v.Expr.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Pass(int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Pass_kind;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Break(int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Break_kind;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+stmt_ty
+Continue(int lineno, int col_offset, PyArena *arena)
+{
+ stmt_ty p;
+ p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Continue_kind;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!op) {
+ PyErr_SetString(PyExc_ValueError,
+ "field op is required for BoolOp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = BoolOp_kind;
+ p->v.BoolOp.op = op;
+ p->v.BoolOp.values = values;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int col_offset,
+ PyArena *arena)
+{
+ expr_ty p;
+ if (!left) {
+ PyErr_SetString(PyExc_ValueError,
+ "field left is required for BinOp");
+ return NULL;
+ }
+ if (!op) {
+ PyErr_SetString(PyExc_ValueError,
+ "field op is required for BinOp");
+ return NULL;
+ }
+ if (!right) {
+ PyErr_SetString(PyExc_ValueError,
+ "field right is required for BinOp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = BinOp_kind;
+ p->v.BinOp.left = left;
+ p->v.BinOp.op = op;
+ p->v.BinOp.right = right;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!op) {
+ PyErr_SetString(PyExc_ValueError,
+ "field op is required for UnaryOp");
+ return NULL;
+ }
+ if (!operand) {
+ PyErr_SetString(PyExc_ValueError,
+ "field operand is required for UnaryOp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = UnaryOp_kind;
+ p->v.UnaryOp.op = op;
+ p->v.UnaryOp.operand = operand;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!args) {
+ PyErr_SetString(PyExc_ValueError,
+ "field args is required for Lambda");
+ return NULL;
+ }
+ if (!body) {
+ PyErr_SetString(PyExc_ValueError,
+ "field body is required for Lambda");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Lambda_kind;
+ p->v.Lambda.args = args;
+ p->v.Lambda.body = body;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int col_offset,
+ PyArena *arena)
+{
+ expr_ty p;
+ if (!test) {
+ PyErr_SetString(PyExc_ValueError,
+ "field test is required for IfExp");
+ return NULL;
+ }
+ if (!body) {
+ PyErr_SetString(PyExc_ValueError,
+ "field body is required for IfExp");
+ return NULL;
+ }
+ if (!orelse) {
+ PyErr_SetString(PyExc_ValueError,
+ "field orelse is required for IfExp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = IfExp_kind;
+ p->v.IfExp.test = test;
+ p->v.IfExp.body = body;
+ p->v.IfExp.orelse = orelse;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Dict(asdl_seq * keys, asdl_seq * values, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Dict_kind;
+ p->v.Dict.keys = keys;
+ p->v.Dict.values = values;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Set_kind;
+ p->v.Set.elts = elts;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset,
+ PyArena *arena)
+{
+ expr_ty p;
+ if (!elt) {
+ PyErr_SetString(PyExc_ValueError,
+ "field elt is required for ListComp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = ListComp_kind;
+ p->v.ListComp.elt = elt;
+ p->v.ListComp.generators = generators;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!elt) {
+ PyErr_SetString(PyExc_ValueError,
+ "field elt is required for SetComp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = SetComp_kind;
+ p->v.SetComp.elt = elt;
+ p->v.SetComp.generators = generators;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int lineno, int
+ col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!key) {
+ PyErr_SetString(PyExc_ValueError,
+ "field key is required for DictComp");
+ return NULL;
+ }
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for DictComp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = DictComp_kind;
+ p->v.DictComp.key = key;
+ p->v.DictComp.value = value;
+ p->v.DictComp.generators = generators;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset,
+ PyArena *arena)
+{
+ expr_ty p;
+ if (!elt) {
+ PyErr_SetString(PyExc_ValueError,
+ "field elt is required for GeneratorExp");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = GeneratorExp_kind;
+ p->v.GeneratorExp.elt = elt;
+ p->v.GeneratorExp.generators = generators;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Yield(expr_ty value, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Yield_kind;
+ p->v.Yield.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, int lineno,
+ int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!left) {
+ PyErr_SetString(PyExc_ValueError,
+ "field left is required for Compare");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Compare_kind;
+ p->v.Compare.left = left;
+ p->v.Compare.ops = ops;
+ p->v.Compare.comparators = comparators;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs,
+ expr_ty kwargs, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!func) {
+ PyErr_SetString(PyExc_ValueError,
+ "field func is required for Call");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Call_kind;
+ p->v.Call.func = func;
+ p->v.Call.args = args;
+ p->v.Call.keywords = keywords;
+ p->v.Call.starargs = starargs;
+ p->v.Call.kwargs = kwargs;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Repr(expr_ty value, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Repr");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Repr_kind;
+ p->v.Repr.value = value;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Num(object n, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!n) {
+ PyErr_SetString(PyExc_ValueError,
+ "field n is required for Num");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Num_kind;
+ p->v.Num.n = n;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Str(string s, int lineno, int col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!s) {
+ PyErr_SetString(PyExc_ValueError,
+ "field s is required for Str");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Str_kind;
+ p->v.Str.s = s;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int
+ col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Attribute");
+ return NULL;
+ }
+ if (!attr) {
+ PyErr_SetString(PyExc_ValueError,
+ "field attr is required for Attribute");
+ return NULL;
+ }
+ if (!ctx) {
+ PyErr_SetString(PyExc_ValueError,
+ "field ctx is required for Attribute");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Attribute_kind;
+ p->v.Attribute.value = value;
+ p->v.Attribute.attr = attr;
+ p->v.Attribute.ctx = ctx;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno, int
+ col_offset, PyArena *arena)
+{
+ expr_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Subscript");
+ return NULL;
+ }
+ if (!slice) {
+ PyErr_SetString(PyExc_ValueError,
+ "field slice is required for Subscript");
+ return NULL;
+ }
+ if (!ctx) {
+ PyErr_SetString(PyExc_ValueError,
+ "field ctx is required for Subscript");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Subscript_kind;
+ p->v.Subscript.value = value;
+ p->v.Subscript.slice = slice;
+ p->v.Subscript.ctx = ctx;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!id) {
+ PyErr_SetString(PyExc_ValueError,
+ "field id is required for Name");
+ return NULL;
+ }
+ if (!ctx) {
+ PyErr_SetString(PyExc_ValueError,
+ "field ctx is required for Name");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Name_kind;
+ p->v.Name.id = id;
+ p->v.Name.ctx = ctx;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+List(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!ctx) {
+ PyErr_SetString(PyExc_ValueError,
+ "field ctx is required for List");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = List_kind;
+ p->v.List.elts = elts;
+ p->v.List.ctx = ctx;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+expr_ty
+Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena
+ *arena)
+{
+ expr_ty p;
+ if (!ctx) {
+ PyErr_SetString(PyExc_ValueError,
+ "field ctx is required for Tuple");
+ return NULL;
+ }
+ p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Tuple_kind;
+ p->v.Tuple.elts = elts;
+ p->v.Tuple.ctx = ctx;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+slice_ty
+Ellipsis(PyArena *arena)
+{
+ slice_ty p;
+ p = (slice_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Ellipsis_kind;
+ return p;
+}
+
+slice_ty
+Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena)
+{
+ slice_ty p;
+ p = (slice_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Slice_kind;
+ p->v.Slice.lower = lower;
+ p->v.Slice.upper = upper;
+ p->v.Slice.step = step;
+ return p;
+}
+
+slice_ty
+ExtSlice(asdl_seq * dims, PyArena *arena)
+{
+ slice_ty p;
+ p = (slice_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = ExtSlice_kind;
+ p->v.ExtSlice.dims = dims;
+ return p;
+}
+
+slice_ty
+Index(expr_ty value, PyArena *arena)
+{
+ slice_ty p;
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for Index");
+ return NULL;
+ }
+ p = (slice_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = Index_kind;
+ p->v.Index.value = value;
+ return p;
+}
+
+comprehension_ty
+comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs, PyArena *arena)
+{
+ comprehension_ty p;
+ if (!target) {
+ PyErr_SetString(PyExc_ValueError,
+ "field target is required for comprehension");
+ return NULL;
+ }
+ if (!iter) {
+ PyErr_SetString(PyExc_ValueError,
+ "field iter is required for comprehension");
+ return NULL;
+ }
+ p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->target = target;
+ p->iter = iter;
+ p->ifs = ifs;
+ return p;
+}
+
+excepthandler_ty
+ExceptHandler(expr_ty type, expr_ty name, asdl_seq * body, int lineno, int
+ col_offset, PyArena *arena)
+{
+ excepthandler_ty p;
+ p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->kind = ExceptHandler_kind;
+ p->v.ExceptHandler.type = type;
+ p->v.ExceptHandler.name = name;
+ p->v.ExceptHandler.body = body;
+ p->lineno = lineno;
+ p->col_offset = col_offset;
+ return p;
+}
+
+arguments_ty
+arguments(asdl_seq * args, identifier vararg, identifier kwarg, asdl_seq *
+ defaults, PyArena *arena)
+{
+ arguments_ty p;
+ p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->args = args;
+ p->vararg = vararg;
+ p->kwarg = kwarg;
+ p->defaults = defaults;
+ return p;
+}
+
+keyword_ty
+keyword(identifier arg, expr_ty value, PyArena *arena)
+{
+ keyword_ty p;
+ if (!arg) {
+ PyErr_SetString(PyExc_ValueError,
+ "field arg is required for keyword");
+ return NULL;
+ }
+ if (!value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field value is required for keyword");
+ return NULL;
+ }
+ p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->arg = arg;
+ p->value = value;
+ return p;
+}
+
+alias_ty
+alias(identifier name, identifier asname, PyArena *arena)
+{
+ alias_ty p;
+ if (!name) {
+ PyErr_SetString(PyExc_ValueError,
+ "field name is required for alias");
+ return NULL;
+ }
+ p = (alias_ty)PyArena_Malloc(arena, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->name = name;
+ p->asname = asname;
+ return p;
+}
+
+
+PyObject*
+ast2obj_mod(void* _o)
+{
+ mod_ty o = (mod_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ switch (o->kind) {
+ case Module_kind:
+ result = PyType_GenericNew(Module_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Module.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Interactive_kind:
+ result = PyType_GenericNew(Interactive_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Expression_kind:
+ result = PyType_GenericNew(Expression_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Expression.body);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Suite_kind:
+ result = PyType_GenericNew(Suite_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Suite.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ }
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_stmt(void* _o)
+{
+ stmt_ty o = (stmt_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ switch (o->kind) {
+ case FunctionDef_kind:
+ result = PyType_GenericNew(FunctionDef_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_identifier(o->v.FunctionDef.name);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "name", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_arguments(o->v.FunctionDef.args);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "args", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.FunctionDef.decorator_list,
+ ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "decorator_list", value) ==
+ -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case ClassDef_kind:
+ result = PyType_GenericNew(ClassDef_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_identifier(o->v.ClassDef.name);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "name", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "bases", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ClassDef.decorator_list,
+ ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "decorator_list", value) ==
+ -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Return_kind:
+ result = PyType_GenericNew(Return_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Return.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Delete_kind:
+ result = PyType_GenericNew(Delete_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Delete.targets, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "targets", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Assign_kind:
+ result = PyType_GenericNew(Assign_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Assign.targets, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "targets", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Assign.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case AugAssign_kind:
+ result = PyType_GenericNew(AugAssign_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.AugAssign.target);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "target", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_operator(o->v.AugAssign.op);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "op", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.AugAssign.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Print_kind:
+ result = PyType_GenericNew(Print_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Print.dest);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "dest", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.Print.values, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "values", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_bool(o->v.Print.nl);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "nl", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case For_kind:
+ result = PyType_GenericNew(For_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.For.target);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "target", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.For.iter);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "iter", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.For.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.For.orelse, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "orelse", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case While_kind:
+ result = PyType_GenericNew(While_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.While.test);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "test", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.While.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.While.orelse, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "orelse", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case If_kind:
+ result = PyType_GenericNew(If_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.If.test);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "test", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.If.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.If.orelse, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "orelse", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case With_kind:
+ result = PyType_GenericNew(With_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.With.context_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "context_expr", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.With.optional_vars);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "optional_vars", value) ==
+ -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.With.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Raise_kind:
+ result = PyType_GenericNew(Raise_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Raise.type);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "type", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Raise.inst);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "inst", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Raise.tback);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "tback", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case TryExcept_kind:
+ result = PyType_GenericNew(TryExcept_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.TryExcept.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.TryExcept.handlers,
+ ast2obj_excepthandler);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "handlers", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.TryExcept.orelse, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "orelse", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case TryFinally_kind:
+ result = PyType_GenericNew(TryFinally_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.TryFinally.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.TryFinally.finalbody, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "finalbody", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Assert_kind:
+ result = PyType_GenericNew(Assert_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Assert.test);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "test", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Assert.msg);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "msg", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Import_kind:
+ result = PyType_GenericNew(Import_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Import.names, ast2obj_alias);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "names", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case ImportFrom_kind:
+ result = PyType_GenericNew(ImportFrom_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_identifier(o->v.ImportFrom.module);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "module", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "names", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_int(o->v.ImportFrom.level);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "level", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Exec_kind:
+ result = PyType_GenericNew(Exec_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Exec.body);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Exec.globals);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "globals", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Exec.locals);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "locals", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Global_kind:
+ result = PyType_GenericNew(Global_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Global.names, ast2obj_identifier);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "names", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Expr_kind:
+ result = PyType_GenericNew(Expr_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Expr.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Pass_kind:
+ result = PyType_GenericNew(Pass_type, NULL, NULL);
+ if (!result) goto failed;
+ break;
+ case Break_kind:
+ result = PyType_GenericNew(Break_type, NULL, NULL);
+ if (!result) goto failed;
+ break;
+ case Continue_kind:
+ result = PyType_GenericNew(Continue_type, NULL, NULL);
+ if (!result) goto failed;
+ break;
+ }
+ value = ast2obj_int(o->lineno);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "lineno", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_int(o->col_offset);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "col_offset", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_expr(void* _o)
+{
+ expr_ty o = (expr_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ switch (o->kind) {
+ case BoolOp_kind:
+ result = PyType_GenericNew(BoolOp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_boolop(o->v.BoolOp.op);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "op", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "values", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case BinOp_kind:
+ result = PyType_GenericNew(BinOp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.BinOp.left);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "left", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_operator(o->v.BinOp.op);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "op", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.BinOp.right);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "right", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case UnaryOp_kind:
+ result = PyType_GenericNew(UnaryOp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_unaryop(o->v.UnaryOp.op);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "op", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.UnaryOp.operand);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "operand", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Lambda_kind:
+ result = PyType_GenericNew(Lambda_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_arguments(o->v.Lambda.args);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "args", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Lambda.body);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case IfExp_kind:
+ result = PyType_GenericNew(IfExp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.IfExp.test);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "test", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.IfExp.body);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.IfExp.orelse);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "orelse", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Dict_kind:
+ result = PyType_GenericNew(Dict_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Dict.keys, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "keys", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.Dict.values, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "values", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Set_kind:
+ result = PyType_GenericNew(Set_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Set.elts, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elts", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case ListComp_kind:
+ result = PyType_GenericNew(ListComp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.ListComp.elt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elt", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ListComp.generators,
+ ast2obj_comprehension);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "generators", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case SetComp_kind:
+ result = PyType_GenericNew(SetComp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.SetComp.elt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elt", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.SetComp.generators,
+ ast2obj_comprehension);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "generators", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case DictComp_kind:
+ result = PyType_GenericNew(DictComp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.DictComp.key);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "key", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.DictComp.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.DictComp.generators,
+ ast2obj_comprehension);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "generators", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case GeneratorExp_kind:
+ result = PyType_GenericNew(GeneratorExp_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.GeneratorExp.elt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elt", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.GeneratorExp.generators,
+ ast2obj_comprehension);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "generators", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Yield_kind:
+ result = PyType_GenericNew(Yield_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Yield.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Compare_kind:
+ result = PyType_GenericNew(Compare_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Compare.left);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "left", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ {
+ int i, n = asdl_seq_LEN(o->v.Compare.ops);
+ value = PyList_New(n);
+ if (!value) goto failed;
+ for(i = 0; i < n; i++)
+ PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i)));
+ }
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ops", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "comparators", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Call_kind:
+ result = PyType_GenericNew(Call_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Call.func);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "func", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.Call.args, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "args", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "keywords", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Call.starargs);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "starargs", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Call.kwargs);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "kwargs", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Repr_kind:
+ result = PyType_GenericNew(Repr_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Repr.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Num_kind:
+ result = PyType_GenericNew(Num_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_object(o->v.Num.n);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "n", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Str_kind:
+ result = PyType_GenericNew(Str_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_string(o->v.Str.s);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "s", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Attribute_kind:
+ result = PyType_GenericNew(Attribute_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Attribute.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_identifier(o->v.Attribute.attr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "attr", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr_context(o->v.Attribute.ctx);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ctx", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Subscript_kind:
+ result = PyType_GenericNew(Subscript_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Subscript.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_slice(o->v.Subscript.slice);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "slice", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr_context(o->v.Subscript.ctx);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ctx", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Name_kind:
+ result = PyType_GenericNew(Name_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_identifier(o->v.Name.id);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "id", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr_context(o->v.Name.ctx);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ctx", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case List_kind:
+ result = PyType_GenericNew(List_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.List.elts, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elts", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr_context(o->v.List.ctx);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ctx", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Tuple_kind:
+ result = PyType_GenericNew(Tuple_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "elts", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr_context(o->v.Tuple.ctx);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ctx", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ }
+ value = ast2obj_int(o->lineno);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "lineno", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_int(o->col_offset);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "col_offset", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject* ast2obj_expr_context(expr_context_ty o)
+{
+ switch(o) {
+ case Load:
+ Py_INCREF(Load_singleton);
+ return Load_singleton;
+ case Store:
+ Py_INCREF(Store_singleton);
+ return Store_singleton;
+ case Del:
+ Py_INCREF(Del_singleton);
+ return Del_singleton;
+ case AugLoad:
+ Py_INCREF(AugLoad_singleton);
+ return AugLoad_singleton;
+ case AugStore:
+ Py_INCREF(AugStore_singleton);
+ return AugStore_singleton;
+ case Param:
+ Py_INCREF(Param_singleton);
+ return Param_singleton;
+ default:
+ /* should never happen, but just in case ... */
+ PyErr_Format(PyExc_SystemError, "unknown expr_context found");
+ return NULL;
+ }
+}
+PyObject*
+ast2obj_slice(void* _o)
+{
+ slice_ty o = (slice_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ switch (o->kind) {
+ case Ellipsis_kind:
+ result = PyType_GenericNew(Ellipsis_type, NULL, NULL);
+ if (!result) goto failed;
+ break;
+ case Slice_kind:
+ result = PyType_GenericNew(Slice_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Slice.lower);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "lower", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Slice.upper);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "upper", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.Slice.step);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "step", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case ExtSlice_kind:
+ result = PyType_GenericNew(ExtSlice_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "dims", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ case Index_kind:
+ result = PyType_GenericNew(Index_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.Index.value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ }
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject* ast2obj_boolop(boolop_ty o)
+{
+ switch(o) {
+ case And:
+ Py_INCREF(And_singleton);
+ return And_singleton;
+ case Or:
+ Py_INCREF(Or_singleton);
+ return Or_singleton;
+ default:
+ /* should never happen, but just in case ... */
+ PyErr_Format(PyExc_SystemError, "unknown boolop found");
+ return NULL;
+ }
+}
+PyObject* ast2obj_operator(operator_ty o)
+{
+ switch(o) {
+ case Add:
+ Py_INCREF(Add_singleton);
+ return Add_singleton;
+ case Sub:
+ Py_INCREF(Sub_singleton);
+ return Sub_singleton;
+ case Mult:
+ Py_INCREF(Mult_singleton);
+ return Mult_singleton;
+ case Div:
+ Py_INCREF(Div_singleton);
+ return Div_singleton;
+ case Mod:
+ Py_INCREF(Mod_singleton);
+ return Mod_singleton;
+ case Pow:
+ Py_INCREF(Pow_singleton);
+ return Pow_singleton;
+ case LShift:
+ Py_INCREF(LShift_singleton);
+ return LShift_singleton;
+ case RShift:
+ Py_INCREF(RShift_singleton);
+ return RShift_singleton;
+ case BitOr:
+ Py_INCREF(BitOr_singleton);
+ return BitOr_singleton;
+ case BitXor:
+ Py_INCREF(BitXor_singleton);
+ return BitXor_singleton;
+ case BitAnd:
+ Py_INCREF(BitAnd_singleton);
+ return BitAnd_singleton;
+ case FloorDiv:
+ Py_INCREF(FloorDiv_singleton);
+ return FloorDiv_singleton;
+ default:
+ /* should never happen, but just in case ... */
+ PyErr_Format(PyExc_SystemError, "unknown operator found");
+ return NULL;
+ }
+}
+PyObject* ast2obj_unaryop(unaryop_ty o)
+{
+ switch(o) {
+ case Invert:
+ Py_INCREF(Invert_singleton);
+ return Invert_singleton;
+ case Not:
+ Py_INCREF(Not_singleton);
+ return Not_singleton;
+ case UAdd:
+ Py_INCREF(UAdd_singleton);
+ return UAdd_singleton;
+ case USub:
+ Py_INCREF(USub_singleton);
+ return USub_singleton;
+ default:
+ /* should never happen, but just in case ... */
+ PyErr_Format(PyExc_SystemError, "unknown unaryop found");
+ return NULL;
+ }
+}
+PyObject* ast2obj_cmpop(cmpop_ty o)
+{
+ switch(o) {
+ case Eq:
+ Py_INCREF(Eq_singleton);
+ return Eq_singleton;
+ case NotEq:
+ Py_INCREF(NotEq_singleton);
+ return NotEq_singleton;
+ case Lt:
+ Py_INCREF(Lt_singleton);
+ return Lt_singleton;
+ case LtE:
+ Py_INCREF(LtE_singleton);
+ return LtE_singleton;
+ case Gt:
+ Py_INCREF(Gt_singleton);
+ return Gt_singleton;
+ case GtE:
+ Py_INCREF(GtE_singleton);
+ return GtE_singleton;
+ case Is:
+ Py_INCREF(Is_singleton);
+ return Is_singleton;
+ case IsNot:
+ Py_INCREF(IsNot_singleton);
+ return IsNot_singleton;
+ case In:
+ Py_INCREF(In_singleton);
+ return In_singleton;
+ case NotIn:
+ Py_INCREF(NotIn_singleton);
+ return NotIn_singleton;
+ default:
+ /* should never happen, but just in case ... */
+ PyErr_Format(PyExc_SystemError, "unknown cmpop found");
+ return NULL;
+ }
+}
+PyObject*
+ast2obj_comprehension(void* _o)
+{
+ comprehension_ty o = (comprehension_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ result = PyType_GenericNew(comprehension_type, NULL, NULL);
+ if (!result) return NULL;
+ value = ast2obj_expr(o->target);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "target", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->iter);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "iter", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->ifs, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "ifs", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_excepthandler(void* _o)
+{
+ excepthandler_ty o = (excepthandler_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ switch (o->kind) {
+ case ExceptHandler_kind:
+ result = PyType_GenericNew(ExceptHandler_type, NULL, NULL);
+ if (!result) goto failed;
+ value = ast2obj_expr(o->v.ExceptHandler.type);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "type", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->v.ExceptHandler.name);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "name", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->v.ExceptHandler.body, ast2obj_stmt);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "body", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ break;
+ }
+ value = ast2obj_int(o->lineno);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "lineno", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_int(o->col_offset);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "col_offset", value) < 0)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_arguments(void* _o)
+{
+ arguments_ty o = (arguments_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ result = PyType_GenericNew(arguments_type, NULL, NULL);
+ if (!result) return NULL;
+ value = ast2obj_list(o->args, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "args", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_identifier(o->vararg);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "vararg", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_identifier(o->kwarg);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "kwarg", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_list(o->defaults, ast2obj_expr);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "defaults", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_keyword(void* _o)
+{
+ keyword_ty o = (keyword_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ result = PyType_GenericNew(keyword_type, NULL, NULL);
+ if (!result) return NULL;
+ value = ast2obj_identifier(o->arg);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "arg", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_expr(o->value);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "value", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyObject*
+ast2obj_alias(void* _o)
+{
+ alias_ty o = (alias_ty)_o;
+ PyObject *result = NULL, *value = NULL;
+ if (!o) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ result = PyType_GenericNew(alias_type, NULL, NULL);
+ if (!result) return NULL;
+ value = ast2obj_identifier(o->name);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "name", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ value = ast2obj_identifier(o->asname);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "asname", value) == -1)
+ goto failed;
+ Py_DECREF(value);
+ return result;
+failed:
+ Py_XDECREF(value);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+
+int
+obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+
+ if (obj == Py_None) {
+ *out = NULL;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Module_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* body;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module");
+ return 1;
+ }
+ *out = Module(body, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Interactive_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* body;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive");
+ return 1;
+ }
+ *out = Interactive(body, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Expression_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty body;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &body, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression");
+ return 1;
+ }
+ *out = Expression(body, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Suite_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* body;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Suite field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite");
+ return 1;
+ }
+ *out = Suite(body, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ int lineno;
+ int col_offset;
+
+ if (obj == Py_None) {
+ *out = NULL;
+ return 0;
+ }
+ if (PyObject_HasAttrString(obj, "lineno")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "lineno");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &lineno, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "col_offset")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "col_offset");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &col_offset, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt");
+ return 1;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ identifier name;
+ arguments_ty args;
+ asdl_seq* body;
+ asdl_seq* decorator_list;
+
+ if (PyObject_HasAttrString(obj, "name")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "name");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &name, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "args")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "args");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_arguments(tmp, &args, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "decorator_list")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "decorator_list");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ decorator_list = asdl_seq_new(len, arena);
+ if (decorator_list == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(decorator_list, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef");
+ return 1;
+ }
+ *out = FunctionDef(name, args, body, decorator_list, lineno,
+ col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ identifier name;
+ asdl_seq* bases;
+ asdl_seq* body;
+ asdl_seq* decorator_list;
+
+ if (PyObject_HasAttrString(obj, "name")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "name");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &name, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "bases")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "bases");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ bases = asdl_seq_new(len, arena);
+ if (bases == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(bases, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "decorator_list")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "decorator_list");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ decorator_list = asdl_seq_new(len, arena);
+ if (decorator_list == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(decorator_list, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef");
+ return 1;
+ }
+ *out = ClassDef(name, bases, body, decorator_list, lineno,
+ col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Return_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ value = NULL;
+ }
+ *out = Return(value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Delete_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* targets;
+
+ if (PyObject_HasAttrString(obj, "targets")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "targets");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ targets = asdl_seq_new(len, arena);
+ if (targets == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(targets, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete");
+ return 1;
+ }
+ *out = Delete(targets, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Assign_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* targets;
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "targets")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "targets");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ targets = asdl_seq_new(len, arena);
+ if (targets == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(targets, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign");
+ return 1;
+ }
+ *out = Assign(targets, value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)AugAssign_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty target;
+ operator_ty op;
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "target")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "target");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &target, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "op")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "op");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_operator(tmp, &op, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign");
+ return 1;
+ }
+ *out = AugAssign(target, op, value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Print_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty dest;
+ asdl_seq* values;
+ bool nl;
+
+ if (PyObject_HasAttrString(obj, "dest")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "dest");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &dest, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ dest = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "values")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "values");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Print field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ values = asdl_seq_new(len, arena);
+ if (values == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Print field \"values\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(values, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Print");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "nl")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "nl");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_bool(tmp, &nl, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"nl\" missing from Print");
+ return 1;
+ }
+ *out = Print(dest, values, nl, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)For_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty target;
+ expr_ty iter;
+ asdl_seq* body;
+ asdl_seq* orelse;
+
+ if (PyObject_HasAttrString(obj, "target")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "target");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &target, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "iter")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "iter");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &iter, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "orelse")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "orelse");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ orelse = asdl_seq_new(len, arena);
+ if (orelse == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(orelse, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For");
+ return 1;
+ }
+ *out = For(target, iter, body, orelse, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)While_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty test;
+ asdl_seq* body;
+ asdl_seq* orelse;
+
+ if (PyObject_HasAttrString(obj, "test")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "test");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &test, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "orelse")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "orelse");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ orelse = asdl_seq_new(len, arena);
+ if (orelse == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(orelse, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While");
+ return 1;
+ }
+ *out = While(test, body, orelse, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)If_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty test;
+ asdl_seq* body;
+ asdl_seq* orelse;
+
+ if (PyObject_HasAttrString(obj, "test")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "test");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &test, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "orelse")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "orelse");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ orelse = asdl_seq_new(len, arena);
+ if (orelse == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(orelse, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If");
+ return 1;
+ }
+ *out = If(test, body, orelse, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)With_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty context_expr;
+ expr_ty optional_vars;
+ asdl_seq* body;
+
+ if (PyObject_HasAttrString(obj, "context_expr")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "context_expr");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &context_expr, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from With");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "optional_vars")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "optional_vars");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &optional_vars, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ optional_vars = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With");
+ return 1;
+ }
+ *out = With(context_expr, optional_vars, body, lineno,
+ col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty type;
+ expr_ty inst;
+ expr_ty tback;
+
+ if (PyObject_HasAttrString(obj, "type")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "type");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &type, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ type = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "inst")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "inst");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &inst, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ inst = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "tback")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "tback");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &tback, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ tback = NULL;
+ }
+ *out = Raise(type, inst, tback, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)TryExcept_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* body;
+ asdl_seq* handlers;
+ asdl_seq* orelse;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "TryExcept field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from TryExcept");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "handlers")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "handlers");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "TryExcept field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ handlers = asdl_seq_new(len, arena);
+ if (handlers == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ excepthandler_ty val;
+ res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"handlers\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(handlers, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from TryExcept");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "orelse")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "orelse");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "TryExcept field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ orelse = asdl_seq_new(len, arena);
+ if (orelse == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"orelse\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(orelse, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from TryExcept");
+ return 1;
+ }
+ *out = TryExcept(body, handlers, orelse, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)TryFinally_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* body;
+ asdl_seq* finalbody;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "TryFinally field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "TryFinally field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from TryFinally");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "finalbody")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "finalbody");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "TryFinally field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ finalbody = asdl_seq_new(len, arena);
+ if (finalbody == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "TryFinally field \"finalbody\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(finalbody, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from TryFinally");
+ return 1;
+ }
+ *out = TryFinally(body, finalbody, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Assert_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty test;
+ expr_ty msg;
+
+ if (PyObject_HasAttrString(obj, "test")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "test");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &test, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "msg")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "msg");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &msg, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ msg = NULL;
+ }
+ *out = Assert(test, msg, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Import_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* names;
+
+ if (PyObject_HasAttrString(obj, "names")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "names");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ names = asdl_seq_new(len, arena);
+ if (names == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ alias_ty val;
+ res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(names, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import");
+ return 1;
+ }
+ *out = Import(names, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)ImportFrom_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ identifier module;
+ asdl_seq* names;
+ int level;
+
+ if (PyObject_HasAttrString(obj, "module")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "module");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &module, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ module = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "names")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "names");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ names = asdl_seq_new(len, arena);
+ if (names == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ alias_ty val;
+ res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(names, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "level")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "level");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &level, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ level = 0;
+ }
+ *out = ImportFrom(module, names, level, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Exec_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty body;
+ expr_ty globals;
+ expr_ty locals;
+
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &body, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Exec");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "globals")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "globals");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &globals, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ globals = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "locals")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "locals");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &locals, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ locals = NULL;
+ }
+ *out = Exec(body, globals, locals, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Global_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* names;
+
+ if (PyObject_HasAttrString(obj, "names")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "names");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ names = asdl_seq_new(len, arena);
+ if (names == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ identifier val;
+ res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(names, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global");
+ return 1;
+ }
+ *out = Global(names, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Expr_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr");
+ return 1;
+ }
+ *out = Expr(value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Pass_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+
+ *out = Pass(lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Break_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+
+ *out = Break(lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Continue_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+
+ *out = Continue(lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ int lineno;
+ int col_offset;
+
+ if (obj == Py_None) {
+ *out = NULL;
+ return 0;
+ }
+ if (PyObject_HasAttrString(obj, "lineno")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "lineno");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &lineno, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "col_offset")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "col_offset");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &col_offset, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr");
+ return 1;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ boolop_ty op;
+ asdl_seq* values;
+
+ if (PyObject_HasAttrString(obj, "op")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "op");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_boolop(tmp, &op, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "values")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "values");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ values = asdl_seq_new(len, arena);
+ if (values == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(values, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp");
+ return 1;
+ }
+ *out = BoolOp(op, values, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)BinOp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty left;
+ operator_ty op;
+ expr_ty right;
+
+ if (PyObject_HasAttrString(obj, "left")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "left");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &left, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "op")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "op");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_operator(tmp, &op, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "right")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "right");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &right, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp");
+ return 1;
+ }
+ *out = BinOp(left, op, right, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)UnaryOp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ unaryop_ty op;
+ expr_ty operand;
+
+ if (PyObject_HasAttrString(obj, "op")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "op");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_unaryop(tmp, &op, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "operand")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "operand");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &operand, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp");
+ return 1;
+ }
+ *out = UnaryOp(op, operand, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Lambda_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ arguments_ty args;
+ expr_ty body;
+
+ if (PyObject_HasAttrString(obj, "args")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "args");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_arguments(tmp, &args, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &body, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda");
+ return 1;
+ }
+ *out = Lambda(args, body, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)IfExp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty test;
+ expr_ty body;
+ expr_ty orelse;
+
+ if (PyObject_HasAttrString(obj, "test")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "test");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &test, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &body, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "orelse")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "orelse");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &orelse, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp");
+ return 1;
+ }
+ *out = IfExp(test, body, orelse, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Dict_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* keys;
+ asdl_seq* values;
+
+ if (PyObject_HasAttrString(obj, "keys")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "keys");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ keys = asdl_seq_new(len, arena);
+ if (keys == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(keys, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "values")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "values");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ values = asdl_seq_new(len, arena);
+ if (values == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(values, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict");
+ return 1;
+ }
+ *out = Dict(keys, values, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Set_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* elts;
+
+ if (PyObject_HasAttrString(obj, "elts")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "elts");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ elts = asdl_seq_new(len, arena);
+ if (elts == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(elts, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set");
+ return 1;
+ }
+ *out = Set(elts, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)ListComp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty elt;
+ asdl_seq* generators;
+
+ if (PyObject_HasAttrString(obj, "elt")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "elt");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &elt, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "generators")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "generators");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ generators = asdl_seq_new(len, arena);
+ if (generators == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ comprehension_ty val;
+ res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(generators, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp");
+ return 1;
+ }
+ *out = ListComp(elt, generators, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)SetComp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty elt;
+ asdl_seq* generators;
+
+ if (PyObject_HasAttrString(obj, "elt")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "elt");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &elt, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "generators")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "generators");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ generators = asdl_seq_new(len, arena);
+ if (generators == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ comprehension_ty val;
+ res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(generators, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp");
+ return 1;
+ }
+ *out = SetComp(elt, generators, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)DictComp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty key;
+ expr_ty value;
+ asdl_seq* generators;
+
+ if (PyObject_HasAttrString(obj, "key")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "key");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &key, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "generators")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "generators");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ generators = asdl_seq_new(len, arena);
+ if (generators == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ comprehension_ty val;
+ res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(generators, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp");
+ return 1;
+ }
+ *out = DictComp(key, value, generators, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)GeneratorExp_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty elt;
+ asdl_seq* generators;
+
+ if (PyObject_HasAttrString(obj, "elt")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "elt");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &elt, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "generators")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "generators");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ generators = asdl_seq_new(len, arena);
+ if (generators == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ comprehension_ty val;
+ res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(generators, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp");
+ return 1;
+ }
+ *out = GeneratorExp(elt, generators, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ value = NULL;
+ }
+ *out = Yield(value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Compare_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty left;
+ asdl_int_seq* ops;
+ asdl_seq* comparators;
+
+ if (PyObject_HasAttrString(obj, "left")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "left");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &left, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ops")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "ops");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ ops = asdl_int_seq_new(len, arena);
+ if (ops == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ cmpop_ty val;
+ res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(ops, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "comparators")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "comparators");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ comparators = asdl_seq_new(len, arena);
+ if (comparators == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(comparators, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare");
+ return 1;
+ }
+ *out = Compare(left, ops, comparators, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Call_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty func;
+ asdl_seq* args;
+ asdl_seq* keywords;
+ expr_ty starargs;
+ expr_ty kwargs;
+
+ if (PyObject_HasAttrString(obj, "func")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "func");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &func, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "args")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "args");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ args = asdl_seq_new(len, arena);
+ if (args == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(args, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "keywords")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "keywords");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ keywords = asdl_seq_new(len, arena);
+ if (keywords == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ keyword_ty val;
+ res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(keywords, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "starargs")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "starargs");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &starargs, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ starargs = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "kwargs")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "kwargs");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &kwargs, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ kwargs = NULL;
+ }
+ *out = Call(func, args, keywords, starargs, kwargs, lineno,
+ col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Repr_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Repr");
+ return 1;
+ }
+ *out = Repr(value, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Num_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ object n;
+
+ if (PyObject_HasAttrString(obj, "n")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "n");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_object(tmp, &n, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num");
+ return 1;
+ }
+ *out = Num(n, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Str_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ string s;
+
+ if (PyObject_HasAttrString(obj, "s")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "s");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_string(tmp, &s, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str");
+ return 1;
+ }
+ *out = Str(s, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+ identifier attr;
+ expr_context_ty ctx;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "attr")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "attr");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &attr, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ctx")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "ctx");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr_context(tmp, &ctx, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute");
+ return 1;
+ }
+ *out = Attribute(value, attr, ctx, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Subscript_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+ slice_ty slice;
+ expr_context_ty ctx;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "slice")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "slice");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_slice(tmp, &slice, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ctx")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "ctx");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr_context(tmp, &ctx, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript");
+ return 1;
+ }
+ *out = Subscript(value, slice, ctx, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Name_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ identifier id;
+ expr_context_ty ctx;
+
+ if (PyObject_HasAttrString(obj, "id")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "id");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &id, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ctx")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "ctx");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr_context(tmp, &ctx, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name");
+ return 1;
+ }
+ *out = Name(id, ctx, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)List_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* elts;
+ expr_context_ty ctx;
+
+ if (PyObject_HasAttrString(obj, "elts")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "elts");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ elts = asdl_seq_new(len, arena);
+ if (elts == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(elts, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ctx")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "ctx");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr_context(tmp, &ctx, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List");
+ return 1;
+ }
+ *out = List(elts, ctx, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Tuple_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* elts;
+ expr_context_ty ctx;
+
+ if (PyObject_HasAttrString(obj, "elts")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "elts");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ elts = asdl_seq_new(len, arena);
+ if (elts == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(elts, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ctx")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "ctx");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr_context(tmp, &ctx, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple");
+ return 1;
+ }
+ *out = Tuple(elts, ctx, lineno, col_offset, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_expr_context(PyObject* obj, expr_context_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Load_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Load;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Store_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Store;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Del_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Del;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)AugLoad_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = AugLoad;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)AugStore_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = AugStore;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Param_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Param;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+
+ if (obj == Py_None) {
+ *out = NULL;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+
+ *out = Ellipsis(arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Slice_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty lower;
+ expr_ty upper;
+ expr_ty step;
+
+ if (PyObject_HasAttrString(obj, "lower")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "lower");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &lower, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ lower = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "upper")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "upper");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &upper, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ upper = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "step")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "step");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &step, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ step = NULL;
+ }
+ *out = Slice(lower, upper, step, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)ExtSlice_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ asdl_seq* dims;
+
+ if (PyObject_HasAttrString(obj, "dims")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "dims");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ dims = asdl_seq_new(len, arena);
+ if (dims == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ slice_ty val;
+ res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ExtSlice field \"dims\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(dims, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice");
+ return 1;
+ }
+ *out = ExtSlice(dims, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)Index_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index");
+ return 1;
+ }
+ *out = Index(value, arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_boolop(PyObject* obj, boolop_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ isinstance = PyObject_IsInstance(obj, (PyObject *)And_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = And;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Or_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Or;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_operator(PyObject* obj, operator_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Add_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Add;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Sub_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Sub;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Mult_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Mult;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Div;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Mod_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Mod;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Pow_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Pow;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)LShift_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = LShift;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)RShift_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = RShift;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)BitOr_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = BitOr;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)BitXor_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = BitXor;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)BitAnd_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = BitAnd;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)FloorDiv_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = FloorDiv;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_unaryop(PyObject* obj, unaryop_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Invert_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Invert;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Not_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Not;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)UAdd_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = UAdd;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)USub_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = USub;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_cmpop(PyObject* obj, cmpop_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Eq_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Eq;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)NotEq_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = NotEq;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Lt_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Lt;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)LtE_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = LtE;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Gt_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Gt;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)GtE_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = GtE;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)Is_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = Is;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)IsNot_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = IsNot;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)In_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = In;
+ return 0;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)NotIn_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = NotIn;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ expr_ty target;
+ expr_ty iter;
+ asdl_seq* ifs;
+
+ if (PyObject_HasAttrString(obj, "target")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "target");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &target, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "iter")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "iter");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &iter, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "ifs")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "ifs");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ ifs = asdl_seq_new(len, arena);
+ if (ifs == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(ifs, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension");
+ return 1;
+ }
+ *out = comprehension(target, iter, ifs, arena);
+ return 0;
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ int isinstance;
+
+ int lineno;
+ int col_offset;
+
+ if (obj == Py_None) {
+ *out = NULL;
+ return 0;
+ }
+ if (PyObject_HasAttrString(obj, "lineno")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "lineno");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &lineno, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "col_offset")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "col_offset");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_int(tmp, &col_offset, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler");
+ return 1;
+ }
+ isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ expr_ty type;
+ expr_ty name;
+ asdl_seq* body;
+
+ if (PyObject_HasAttrString(obj, "type")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "type");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &type, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ type = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "name")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "name");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &name, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ name = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "body")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "body");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ body = asdl_seq_new(len, arena);
+ if (body == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ stmt_ty val;
+ res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(body, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler");
+ return 1;
+ }
+ *out = ExceptHandler(type, name, body, lineno, col_offset,
+ arena);
+ if (*out == NULL) goto failed;
+ return 0;
+ }
+
+ tmp = PyObject_Repr(obj);
+ if (tmp == NULL) goto failed;
+ PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %.400s", PyString_AS_STRING(tmp));
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ asdl_seq* args;
+ identifier vararg;
+ identifier kwarg;
+ asdl_seq* defaults;
+
+ if (PyObject_HasAttrString(obj, "args")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "args");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ args = asdl_seq_new(len, arena);
+ if (args == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(args, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "vararg")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "vararg");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &vararg, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ vararg = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "kwarg")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "kwarg");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &kwarg, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ kwarg = NULL;
+ }
+ if (PyObject_HasAttrString(obj, "defaults")) {
+ int res;
+ Py_ssize_t len;
+ Py_ssize_t i;
+ tmp = PyObject_GetAttrString(obj, "defaults");
+ if (tmp == NULL) goto failed;
+ if (!PyList_Check(tmp)) {
+ PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name);
+ goto failed;
+ }
+ len = PyList_GET_SIZE(tmp);
+ defaults = asdl_seq_new(len, arena);
+ if (defaults == NULL) goto failed;
+ for (i = 0; i < len; i++) {
+ expr_ty val;
+ res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &val, arena);
+ if (res != 0) goto failed;
+ if (len != PyList_GET_SIZE(tmp)) {
+ PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration");
+ goto failed;
+ }
+ asdl_seq_SET(defaults, i, val);
+ }
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments");
+ return 1;
+ }
+ *out = arguments(args, vararg, kwarg, defaults, arena);
+ return 0;
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ identifier arg;
+ expr_ty value;
+
+ if (PyObject_HasAttrString(obj, "arg")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "arg");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &arg, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_expr(tmp, &value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword");
+ return 1;
+ }
+ *out = keyword(arg, value, arena);
+ return 0;
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+int
+obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena)
+{
+ PyObject* tmp = NULL;
+ identifier name;
+ identifier asname;
+
+ if (PyObject_HasAttrString(obj, "name")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "name");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &name, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias");
+ return 1;
+ }
+ if (PyObject_HasAttrString(obj, "asname")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "asname");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &asname, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ asname = NULL;
+ }
+ *out = alias(name, asname, arena);
+ return 0;
+failed:
+ Py_XDECREF(tmp);
+ return 1;
+}
+
+
+PyMODINIT_FUNC
+init_ast(void)
+{
+ PyObject *m, *d;
+ if (!init_types()) return;
+ m = Py_InitModule3("_ast", NULL, NULL);
+ if (!m) return;
+ d = PyModule_GetDict(m);
+ if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return;
+ if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
+ return;
+ if (PyModule_AddStringConstant(m, "__version__", "82160") < 0)
+ return;
+ if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
+ if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type)
+ < 0) return;
+ if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return;
+ if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return;
+ if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type)
+ < 0) return;
+ if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Print", (PyObject*)Print_type) < 0) return;
+ if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return;
+ if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return;
+ if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return;
+ if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return;
+ if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return;
+ if (PyDict_SetItemString(d, "TryExcept", (PyObject*)TryExcept_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "TryFinally", (PyObject*)TryFinally_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Exec", (PyObject*)Exec_type) < 0) return;
+ if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return;
+ if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return;
+ if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return;
+ if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return;
+ if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return;
+ if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return;
+ if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return;
+ if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return;
+ if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "GeneratorExp",
+ (PyObject*)GeneratorExp_type) < 0) return;
+ if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return;
+ if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return;
+ if (PyDict_SetItemString(d, "Repr", (PyObject*)Repr_type) < 0) return;
+ if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return;
+ if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return;
+ if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return;
+ if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return;
+ if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return;
+ if (PyDict_SetItemString(d, "expr_context",
+ (PyObject*)expr_context_type) < 0) return;
+ if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return;
+ if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return;
+ if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return;
+ if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return;
+ if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return;
+ if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return;
+ if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return;
+ if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return;
+ if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return;
+ if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return;
+ if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return;
+ if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return;
+ if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return;
+ if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return;
+ if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return;
+ if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return;
+ if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return;
+ if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return;
+ if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return;
+ if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return;
+ if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return;
+ if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return;
+ if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return;
+ if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return;
+ if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return;
+ if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return;
+ if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return;
+ if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return;
+ if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return;
+ if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return;
+ if (PyDict_SetItemString(d, "comprehension",
+ (PyObject*)comprehension_type) < 0) return;
+ if (PyDict_SetItemString(d, "excepthandler",
+ (PyObject*)excepthandler_type) < 0) return;
+ if (PyDict_SetItemString(d, "ExceptHandler",
+ (PyObject*)ExceptHandler_type) < 0) return;
+ if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) <
+ 0) return;
+ if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0)
+ return;
+ if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return;
+}
+
+
+PyObject* PyAST_mod2obj(mod_ty t)
+{
+ init_types();
+ return ast2obj_mod(t);
+}
+
+/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
+mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
+{
+ mod_ty res;
+ PyObject *req_type[3];
+ char *req_name[3];
+ int isinstance;
+
+ req_type[0] = (PyObject*)Module_type;
+ req_type[1] = (PyObject*)Expression_type;
+ req_type[2] = (PyObject*)Interactive_type;
+
+ req_name[0] = "Module";
+ req_name[1] = "Expression";
+ req_name[2] = "Interactive";
+
+ assert(0 <= mode && mode <= 2);
+
+ init_types();
+
+ isinstance = PyObject_IsInstance(ast, req_type[mode]);
+ if (isinstance == -1)
+ return NULL;
+ if (!isinstance) {
+ PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
+ req_name[mode], Py_TYPE(ast)->tp_name);
+ return NULL;
+ }
+ if (obj2ast_mod(ast, &res, arena) != 0)
+ return NULL;
+ else
+ return res;
+}
+
+int PyAST_Check(PyObject* obj)
+{
+ init_types();
+ return PyObject_IsInstance(obj, (PyObject*)&AST_type);
+}
+
+
diff --git a/contrib/tools/python/src/Python/_warnings.c b/contrib/tools/python/src/Python/_warnings.c
new file mode 100644
index 0000000000..37875e5619
--- /dev/null
+++ b/contrib/tools/python/src/Python/_warnings.c
@@ -0,0 +1,917 @@
+#include "Python.h"
+#include "frameobject.h"
+
+#define MODULE_NAME "_warnings"
+
+PyDoc_STRVAR(warnings__doc__,
+MODULE_NAME " provides basic warning filtering support.\n"
+"It is a helper module to speed up interpreter start-up.");
+
+/* Both 'filters' and 'onceregistry' can be set in warnings.py;
+ get_warnings_attr() will reset these variables accordingly. */
+static PyObject *_filters; /* List */
+static PyObject *_once_registry; /* Dict */
+static PyObject *_default_action; /* String */
+
+
+static int
+check_matched(PyObject *obj, PyObject *arg)
+{
+ PyObject *result;
+ int rc;
+
+ if (obj == Py_None)
+ return 1;
+ result = PyObject_CallMethod(obj, "match", "O", arg);
+ if (result == NULL)
+ return -1;
+
+ rc = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ return rc;
+}
+
+/*
+ Returns a new reference.
+ A NULL return value can mean false or an error.
+*/
+static PyObject *
+get_warnings_attr(const char *attr)
+{
+ static PyObject *warnings_str = NULL;
+ PyObject *all_modules;
+ PyObject *warnings_module;
+ int result;
+
+ if (warnings_str == NULL) {
+ warnings_str = PyString_InternFromString("warnings");
+ if (warnings_str == NULL)
+ return NULL;
+ }
+
+ all_modules = PyImport_GetModuleDict();
+ result = PyDict_Contains(all_modules, warnings_str);
+ if (result == -1 || result == 0)
+ return NULL;
+
+ warnings_module = PyDict_GetItem(all_modules, warnings_str);
+ if (!PyObject_HasAttrString(warnings_module, attr))
+ return NULL;
+ return PyObject_GetAttrString(warnings_module, attr);
+}
+
+
+static PyObject *
+get_once_registry(void)
+{
+ PyObject *registry;
+
+ registry = get_warnings_attr("onceregistry");
+ if (registry == NULL) {
+ if (PyErr_Occurred())
+ return NULL;
+ return _once_registry;
+ }
+ if (!PyDict_Check(registry)) {
+ PyErr_SetString(PyExc_TypeError,
+ "warnings.onceregistry must be a dict");
+ Py_DECREF(registry);
+ return NULL;
+ }
+ Py_DECREF(_once_registry);
+ _once_registry = registry;
+ return registry;
+}
+
+
+static PyObject *
+get_default_action(void)
+{
+ PyObject *default_action;
+
+ default_action = get_warnings_attr("defaultaction");
+ if (default_action == NULL) {
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ return _default_action;
+ }
+
+ Py_DECREF(_default_action);
+ _default_action = default_action;
+ return default_action;
+}
+
+
+/* The item is a borrowed reference. */
+static const char *
+get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
+ PyObject *module, PyObject **item)
+{
+ PyObject *action;
+ Py_ssize_t i;
+ PyObject *warnings_filters;
+
+ warnings_filters = get_warnings_attr("filters");
+ if (warnings_filters == NULL) {
+ if (PyErr_Occurred())
+ return NULL;
+ }
+ else {
+ Py_DECREF(_filters);
+ _filters = warnings_filters;
+ }
+
+ if (!PyList_Check(_filters)) {
+ PyErr_SetString(PyExc_ValueError,
+ MODULE_NAME ".filters must be a list");
+ return NULL;
+ }
+
+ /* _filters could change while we are iterating over it. */
+ for (i = 0; i < PyList_GET_SIZE(_filters); i++) {
+ PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
+ Py_ssize_t ln;
+ int is_subclass, good_msg, good_mod;
+
+ tmp_item = *item = PyList_GET_ITEM(_filters, i);
+ if (PyTuple_Size(tmp_item) != 5) {
+ PyErr_Format(PyExc_ValueError,
+ MODULE_NAME ".filters item %zd isn't a 5-tuple", i);
+ return NULL;
+ }
+
+ /* Python code: action, msg, cat, mod, ln = item */
+ action = PyTuple_GET_ITEM(tmp_item, 0);
+ msg = PyTuple_GET_ITEM(tmp_item, 1);
+ cat = PyTuple_GET_ITEM(tmp_item, 2);
+ mod = PyTuple_GET_ITEM(tmp_item, 3);
+ ln_obj = PyTuple_GET_ITEM(tmp_item, 4);
+
+ good_msg = check_matched(msg, text);
+ good_mod = check_matched(mod, module);
+ is_subclass = PyObject_IsSubclass(category, cat);
+ ln = PyInt_AsSsize_t(ln_obj);
+ if (good_msg == -1 || good_mod == -1 || is_subclass == -1 ||
+ (ln == -1 && PyErr_Occurred()))
+ return NULL;
+
+ if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln))
+ return PyString_AsString(action);
+ }
+
+ action = get_default_action();
+ if (action != NULL) {
+ return PyString_AsString(action);
+ }
+
+ PyErr_SetString(PyExc_ValueError,
+ MODULE_NAME ".defaultaction not found");
+ return NULL;
+}
+
+
+static int
+already_warned(PyObject *registry, PyObject *key, int should_set)
+{
+ PyObject *already_warned;
+
+ if (key == NULL)
+ return -1;
+
+ already_warned = PyDict_GetItem(registry, key);
+ if (already_warned != NULL) {
+ int rc = PyObject_IsTrue(already_warned);
+ if (rc != 0)
+ return rc;
+ }
+
+ /* This warning wasn't found in the registry, set it. */
+ if (should_set)
+ return PyDict_SetItem(registry, key, Py_True);
+ return 0;
+}
+
+/* New reference. */
+static PyObject *
+normalize_module(PyObject *filename)
+{
+ PyObject *module;
+ const char *mod_str;
+ Py_ssize_t len;
+
+ int rc = PyObject_IsTrue(filename);
+ if (rc == -1)
+ return NULL;
+ else if (rc == 0)
+ return PyString_FromString("<unknown>");
+
+ mod_str = PyString_AsString(filename);
+ if (mod_str == NULL)
+ return NULL;
+ len = PyString_Size(filename);
+ if (len < 0)
+ return NULL;
+ if (len >= 3 &&
+ strncmp(mod_str + (len - 3), ".py", 3) == 0) {
+ module = PyString_FromStringAndSize(mod_str, len-3);
+ }
+ else {
+ module = filename;
+ Py_INCREF(module);
+ }
+ return module;
+}
+
+static int
+update_registry(PyObject *registry, PyObject *text, PyObject *category,
+ int add_zero)
+{
+ PyObject *altkey, *zero = NULL;
+ int rc;
+
+ if (add_zero) {
+ zero = PyInt_FromLong(0);
+ if (zero == NULL)
+ return -1;
+ altkey = PyTuple_Pack(3, text, category, zero);
+ }
+ else
+ altkey = PyTuple_Pack(2, text, category);
+
+ rc = already_warned(registry, altkey, 1);
+ Py_XDECREF(zero);
+ Py_XDECREF(altkey);
+ return rc;
+}
+
+static void
+show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
+ *category, PyObject *sourceline)
+{
+ PyObject *f_stderr;
+ PyObject *name;
+ char lineno_str[128];
+
+ PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
+
+ name = PyObject_GetAttrString(category, "__name__");
+ if (name == NULL) /* XXX Can an object lack a '__name__' attribute? */
+ return;
+
+ f_stderr = PySys_GetObject("stderr");
+ if (f_stderr == NULL) {
+ fprintf(stderr, "lost sys.stderr\n");
+ Py_DECREF(name);
+ return;
+ }
+
+ /* Print "filename:lineno: category: text\n" */
+ PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW);
+ PyFile_WriteString(lineno_str, f_stderr);
+ PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW);
+ PyFile_WriteString(": ", f_stderr);
+ PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW);
+ PyFile_WriteString("\n", f_stderr);
+ Py_XDECREF(name);
+
+ /* Print " source_line\n" */
+ if (sourceline) {
+ char *source_line_str = PyString_AS_STRING(sourceline);
+ while (*source_line_str == ' ' || *source_line_str == '\t' ||
+ *source_line_str == '\014')
+ source_line_str++;
+
+ PyFile_WriteString(source_line_str, f_stderr);
+ PyFile_WriteString("\n", f_stderr);
+ }
+ else
+ _Py_DisplaySourceLine(f_stderr, PyString_AS_STRING(filename),
+ lineno, 2);
+ PyErr_Clear();
+}
+
+static PyObject *
+warn_explicit(PyObject *category, PyObject *message,
+ PyObject *filename, int lineno,
+ PyObject *module, PyObject *registry, PyObject *sourceline)
+{
+ PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
+ PyObject *item = Py_None;
+ const char *action;
+ int rc;
+
+ if (registry && !PyDict_Check(registry) && (registry != Py_None)) {
+ PyErr_SetString(PyExc_TypeError, "'registry' must be a dict or None");
+ return NULL;
+ }
+
+ /* Normalize module. */
+ if (module == NULL) {
+ module = normalize_module(filename);
+ if (module == NULL)
+ return NULL;
+ }
+ else
+ Py_INCREF(module);
+
+ /* Normalize message. */
+ Py_INCREF(message); /* DECREF'ed in cleanup. */
+ rc = PyObject_IsInstance(message, PyExc_Warning);
+ if (rc == -1) {
+ goto cleanup;
+ }
+ if (rc == 1) {
+ text = PyObject_Str(message);
+ if (text == NULL)
+ goto cleanup;
+ category = (PyObject*)message->ob_type;
+ }
+ else {
+ text = message;
+ message = PyObject_CallFunction(category, "O", message);
+ if (message == NULL)
+ goto cleanup;
+ }
+
+ lineno_obj = PyInt_FromLong(lineno);
+ if (lineno_obj == NULL)
+ goto cleanup;
+
+ /* Create key. */
+ key = PyTuple_Pack(3, text, category, lineno_obj);
+ if (key == NULL)
+ goto cleanup;
+
+ if ((registry != NULL) && (registry != Py_None)) {
+ rc = already_warned(registry, key, 0);
+ if (rc == -1)
+ goto cleanup;
+ else if (rc == 1)
+ goto return_none;
+ /* Else this warning hasn't been generated before. */
+ }
+
+ action = get_filter(category, text, lineno, module, &item);
+ if (action == NULL)
+ goto cleanup;
+
+ if (strcmp(action, "error") == 0) {
+ PyErr_SetObject(category, message);
+ goto cleanup;
+ }
+
+ /* Store in the registry that we've been here, *except* when the action
+ is "always". */
+ rc = 0;
+ if (strcmp(action, "always") != 0) {
+ if (registry != NULL && registry != Py_None &&
+ PyDict_SetItem(registry, key, Py_True) < 0)
+ goto cleanup;
+ else if (strcmp(action, "ignore") == 0)
+ goto return_none;
+ else if (strcmp(action, "once") == 0) {
+ if (registry == NULL || registry == Py_None) {
+ registry = get_once_registry();
+ if (registry == NULL)
+ goto cleanup;
+ }
+ /* _once_registry[(text, category)] = 1 */
+ rc = update_registry(registry, text, category, 0);
+ }
+ else if (strcmp(action, "module") == 0) {
+ /* registry[(text, category, 0)] = 1 */
+ if (registry != NULL && registry != Py_None)
+ rc = update_registry(registry, text, category, 0);
+ }
+ else if (strcmp(action, "default") != 0) {
+ PyObject *to_str = PyObject_Str(item);
+ const char *err_str = "???";
+
+ if (to_str != NULL)
+ err_str = PyString_AS_STRING(to_str);
+ PyErr_Format(PyExc_RuntimeError,
+ "Unrecognized action (%s) in warnings.filters:\n %s",
+ action, err_str);
+ Py_XDECREF(to_str);
+ goto cleanup;
+ }
+ }
+
+ if (rc == 1) /* Already warned for this module. */
+ goto return_none;
+ if (rc == 0) {
+ PyObject *show_fxn = get_warnings_attr("showwarning");
+ if (show_fxn == NULL) {
+ if (PyErr_Occurred())
+ goto cleanup;
+ show_warning(filename, lineno, text, category, sourceline);
+ }
+ else {
+ PyObject *res;
+
+ if (!PyMethod_Check(show_fxn) && !PyFunction_Check(show_fxn)) {
+ PyErr_SetString(PyExc_TypeError,
+ "warnings.showwarning() must be set to a "
+ "function or method");
+ Py_DECREF(show_fxn);
+ goto cleanup;
+ }
+
+ res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
+ filename, lineno_obj,
+ NULL);
+ Py_DECREF(show_fxn);
+ Py_XDECREF(res);
+ if (res == NULL)
+ goto cleanup;
+ }
+ }
+ else /* if (rc == -1) */
+ goto cleanup;
+
+ return_none:
+ result = Py_None;
+ Py_INCREF(result);
+
+ cleanup:
+ Py_XDECREF(key);
+ Py_XDECREF(text);
+ Py_XDECREF(lineno_obj);
+ Py_DECREF(module);
+ Py_XDECREF(message);
+ return result; /* Py_None or NULL. */
+}
+
+/* filename, module, and registry are new refs, globals is borrowed */
+/* Returns 0 on error (no new refs), 1 on success */
+static int
+setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
+ PyObject **module, PyObject **registry)
+{
+ PyObject *globals;
+
+ /* Setup globals and lineno. */
+ PyFrameObject *f = PyThreadState_GET()->frame;
+ while (--stack_level > 0 && f != NULL)
+ f = f->f_back;
+
+ if (f == NULL) {
+ globals = PyThreadState_Get()->interp->sysdict;
+ *lineno = 1;
+ }
+ else {
+ globals = f->f_globals;
+ *lineno = PyFrame_GetLineNumber(f);
+ }
+
+ *module = NULL;
+
+ /* Setup registry. */
+ assert(globals != NULL);
+ assert(PyDict_Check(globals));
+ *registry = PyDict_GetItemString(globals, "__warningregistry__");
+ if (*registry == NULL) {
+ int rc;
+
+ *registry = PyDict_New();
+ if (*registry == NULL)
+ return 0;
+
+ rc = PyDict_SetItemString(globals, "__warningregistry__", *registry);
+ if (rc < 0)
+ goto handle_error;
+ }
+ else
+ Py_INCREF(*registry);
+
+ /* Setup module. */
+ *module = PyDict_GetItemString(globals, "__name__");
+ if (*module == NULL) {
+ *module = PyString_FromString("<string>");
+ if (*module == NULL)
+ goto handle_error;
+ }
+ else
+ Py_INCREF(*module);
+
+ /* Setup filename. */
+ *filename = PyDict_GetItemString(globals, "__file__");
+ if (*filename != NULL && PyString_Check(*filename)) {
+ Py_ssize_t len = PyString_Size(*filename);
+ const char *file_str = PyString_AsString(*filename);
+ if (file_str == NULL || (len < 0 && PyErr_Occurred()))
+ goto handle_error;
+
+ /* if filename.lower().endswith((".pyc", ".pyo")): */
+ if (len >= 4 &&
+ file_str[len-4] == '.' &&
+ tolower(file_str[len-3]) == 'p' &&
+ tolower(file_str[len-2]) == 'y' &&
+ (tolower(file_str[len-1]) == 'c' ||
+ tolower(file_str[len-1]) == 'o'))
+ {
+ *filename = PyString_FromStringAndSize(file_str, len-1);
+ if (*filename == NULL)
+ goto handle_error;
+ }
+ else
+ Py_INCREF(*filename);
+ }
+ else {
+ const char *module_str = PyString_AsString(*module);
+ *filename = NULL;
+ if (module_str && strcmp(module_str, "__main__") == 0) {
+ PyObject *argv = PySys_GetObject("argv");
+ if (argv != NULL && PyList_Size(argv) > 0) {
+ int is_true;
+ *filename = PyList_GetItem(argv, 0);
+ Py_INCREF(*filename);
+ /* If sys.argv[0] is false, then use '__main__'. */
+ is_true = PyObject_IsTrue(*filename);
+ if (is_true < 0) {
+ Py_DECREF(*filename);
+ goto handle_error;
+ }
+ else if (!is_true) {
+ Py_SETREF(*filename, PyString_FromString("__main__"));
+ if (*filename == NULL)
+ goto handle_error;
+ }
+ }
+ else {
+ /* embedded interpreters don't have sys.argv, see bug #839151 */
+ *filename = PyString_FromString("__main__");
+ if (*filename == NULL)
+ goto handle_error;
+ }
+ }
+ if (*filename == NULL) {
+ *filename = *module;
+ Py_INCREF(*filename);
+ }
+ }
+
+ return 1;
+
+ handle_error:
+ /* filename not XDECREF'ed here as there is no way to jump here with a
+ dangling reference. */
+ Py_XDECREF(*registry);
+ Py_XDECREF(*module);
+ return 0;
+}
+
+static PyObject *
+get_category(PyObject *message, PyObject *category)
+{
+ int rc;
+
+ /* Get category. */
+ rc = PyObject_IsInstance(message, PyExc_Warning);
+ if (rc == -1)
+ return NULL;
+
+ if (rc == 1)
+ category = (PyObject*)message->ob_type;
+ else if (category == NULL)
+ category = PyExc_UserWarning;
+
+ /* Validate category. */
+ rc = PyObject_IsSubclass(category, PyExc_Warning);
+ if (rc == -1)
+ return NULL;
+ if (rc == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "category is not a subclass of Warning");
+ return NULL;
+ }
+
+ return category;
+}
+
+static PyObject *
+do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level)
+{
+ PyObject *filename, *module, *registry, *res;
+ int lineno;
+
+ if (!setup_context(stack_level, &filename, &lineno, &module, &registry))
+ return NULL;
+
+ res = warn_explicit(category, message, filename, lineno, module, registry,
+ NULL);
+ Py_DECREF(filename);
+ Py_DECREF(registry);
+ Py_DECREF(module);
+ return res;
+}
+
+static PyObject *
+warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kw_list[] = { "message", "category", "stacklevel", 0 };
+ PyObject *message, *category = NULL;
+ Py_ssize_t stack_level = 1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
+ &message, &category, &stack_level))
+ return NULL;
+
+ category = get_category(message, category);
+ if (category == NULL)
+ return NULL;
+ return do_warn(message, category, stack_level);
+}
+
+static PyObject *
+warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwd_list[] = {"message", "category", "filename", "lineno",
+ "module", "registry", "module_globals", 0};
+ PyObject *message;
+ PyObject *category;
+ PyObject *filename;
+ int lineno;
+ PyObject *module = NULL;
+ PyObject *registry = NULL;
+ PyObject *module_globals = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOi|OOO:warn_explicit",
+ kwd_list, &message, &category, &filename, &lineno, &module,
+ &registry, &module_globals))
+ return NULL;
+
+ if (module_globals) {
+ static PyObject *get_source_name = NULL;
+ static PyObject *splitlines_name = NULL;
+ PyObject *loader;
+ PyObject *module_name;
+ PyObject *source;
+ PyObject *source_list;
+ PyObject *source_line;
+ PyObject *returned;
+
+ if (get_source_name == NULL) {
+ get_source_name = PyString_InternFromString("get_source");
+ if (!get_source_name)
+ return NULL;
+ }
+ if (splitlines_name == NULL) {
+ splitlines_name = PyString_InternFromString("splitlines");
+ if (!splitlines_name)
+ return NULL;
+ }
+
+ /* Check/get the requisite pieces needed for the loader. */
+ loader = PyDict_GetItemString(module_globals, "__loader__");
+ module_name = PyDict_GetItemString(module_globals, "__name__");
+
+ if (loader == NULL || module_name == NULL)
+ goto standard_call;
+
+ /* Make sure the loader implements the optional get_source() method. */
+ if (!PyObject_HasAttrString(loader, "get_source"))
+ goto standard_call;
+ /* Call get_source() to get the source code. */
+ source = PyObject_CallMethodObjArgs(loader, get_source_name,
+ module_name, NULL);
+ if (!source)
+ return NULL;
+ else if (source == Py_None) {
+ Py_DECREF(Py_None);
+ goto standard_call;
+ }
+
+ /* Split the source into lines. */
+ source_list = PyObject_CallMethodObjArgs((PyObject *)&PyString_Type,
+ splitlines_name, source,
+ NULL);
+ Py_DECREF(source);
+ if (!source_list)
+ return NULL;
+
+ /* Get the source line. */
+ source_line = PyList_GetItem(source_list, lineno-1);
+ if (!source_line) {
+ Py_DECREF(source_list);
+ return NULL;
+ }
+
+ /* Handle the warning. */
+ returned = warn_explicit(category, message, filename, lineno, module,
+ registry, source_line);
+ Py_DECREF(source_list);
+ return returned;
+ }
+
+ standard_call:
+ return warn_explicit(category, message, filename, lineno, module,
+ registry, NULL);
+}
+
+
+/* Function to issue a warning message; may raise an exception. */
+int
+PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
+{
+ PyObject *res;
+ PyObject *message = PyString_FromString(text);
+ if (message == NULL)
+ return -1;
+
+ if (category == NULL)
+ category = PyExc_RuntimeWarning;
+
+ res = do_warn(message, category, stack_level);
+ Py_DECREF(message);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+
+ return 0;
+}
+
+/* PyErr_Warn is only for backwards compatibility and will be removed.
+ Use PyErr_WarnEx instead. */
+
+#undef PyErr_Warn
+
+PyAPI_FUNC(int)
+PyErr_Warn(PyObject *category, char *text)
+{
+ return PyErr_WarnEx(category, text, 1);
+}
+
+/* Warning with explicit origin */
+int
+PyErr_WarnExplicit(PyObject *category, const char *text,
+ const char *filename_str, int lineno,
+ const char *module_str, PyObject *registry)
+{
+ PyObject *res;
+ PyObject *message = PyString_FromString(text);
+ PyObject *filename = PyString_FromString(filename_str);
+ PyObject *module = NULL;
+ int ret = -1;
+
+ if (message == NULL || filename == NULL)
+ goto exit;
+ if (module_str != NULL) {
+ module = PyString_FromString(module_str);
+ if (module == NULL)
+ goto exit;
+ }
+
+ if (category == NULL)
+ category = PyExc_RuntimeWarning;
+ res = warn_explicit(category, message, filename, lineno, module, registry,
+ NULL);
+ if (res == NULL)
+ goto exit;
+ Py_DECREF(res);
+ ret = 0;
+
+ exit:
+ Py_XDECREF(message);
+ Py_XDECREF(module);
+ Py_XDECREF(filename);
+ return ret;
+}
+
+
+PyDoc_STRVAR(warn_doc,
+"Issue a warning, or maybe ignore it or raise an exception.");
+
+PyDoc_STRVAR(warn_explicit_doc,
+"Low-level inferface to warnings functionality.");
+
+static PyMethodDef warnings_functions[] = {
+ {"warn", (PyCFunction)warnings_warn, METH_VARARGS | METH_KEYWORDS,
+ warn_doc},
+ {"warn_explicit", (PyCFunction)warnings_warn_explicit,
+ METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
+ /* XXX(brett.cannon): add showwarning? */
+ /* XXX(brett.cannon): Reasonable to add formatwarning? */
+ {NULL, NULL} /* sentinel */
+};
+
+
+static PyObject *
+create_filter(PyObject *category, const char *action)
+{
+ static PyObject *ignore_str = NULL;
+ static PyObject *error_str = NULL;
+ static PyObject *default_str = NULL;
+ PyObject *action_obj = NULL;
+ PyObject *lineno, *result;
+
+ if (!strcmp(action, "ignore")) {
+ if (ignore_str == NULL) {
+ ignore_str = PyString_InternFromString("ignore");
+ if (ignore_str == NULL)
+ return NULL;
+ }
+ action_obj = ignore_str;
+ }
+ else if (!strcmp(action, "error")) {
+ if (error_str == NULL) {
+ error_str = PyString_InternFromString("error");
+ if (error_str == NULL)
+ return NULL;
+ }
+ action_obj = error_str;
+ }
+ else if (!strcmp(action, "default")) {
+ if (default_str == NULL) {
+ default_str = PyString_InternFromString("default");
+ if (default_str == NULL)
+ return NULL;
+ }
+ action_obj = default_str;
+ }
+ else {
+ Py_FatalError("unknown action");
+ }
+
+ /* This assumes the line number is zero for now. */
+ lineno = PyInt_FromLong(0);
+ if (lineno == NULL)
+ return NULL;
+ result = PyTuple_Pack(5, action_obj, Py_None, category, Py_None, lineno);
+ Py_DECREF(lineno);
+ return result;
+}
+
+static PyObject *
+init_filters(void)
+{
+ /* Don't silence DeprecationWarning if -3 or -Q were used. */
+ PyObject *filters = PyList_New(Py_Py3kWarningFlag ||
+ Py_DivisionWarningFlag ? 3 : 4);
+ unsigned int pos = 0; /* Post-incremented in each use. */
+ unsigned int x;
+ const char *bytes_action;
+
+ if (filters == NULL)
+ return NULL;
+
+ /* If guard changes, make sure to update 'filters' initialization above. */
+ if (!Py_Py3kWarningFlag && !Py_DivisionWarningFlag) {
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_DeprecationWarning, "ignore"));
+ }
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_PendingDeprecationWarning, "ignore"));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_ImportWarning, "ignore"));
+ if (Py_BytesWarningFlag > 1)
+ bytes_action = "error";
+ else if (Py_BytesWarningFlag)
+ bytes_action = "default";
+ else
+ bytes_action = "ignore";
+ PyList_SET_ITEM(filters, pos++, create_filter(PyExc_BytesWarning,
+ bytes_action));
+
+ for (x = 0; x < pos; x += 1) {
+ if (PyList_GET_ITEM(filters, x) == NULL) {
+ Py_DECREF(filters);
+ return NULL;
+ }
+ }
+
+ return filters;
+}
+
+
+PyMODINIT_FUNC
+_PyWarnings_Init(void)
+{
+ PyObject *m;
+
+ m = Py_InitModule3(MODULE_NAME, warnings_functions, warnings__doc__);
+ if (m == NULL)
+ return;
+
+ _filters = init_filters();
+ if (_filters == NULL)
+ return;
+ Py_INCREF(_filters);
+ if (PyModule_AddObject(m, "filters", _filters) < 0)
+ return;
+
+ _once_registry = PyDict_New();
+ if (_once_registry == NULL)
+ return;
+ Py_INCREF(_once_registry);
+ if (PyModule_AddObject(m, "once_registry", _once_registry) < 0)
+ return;
+
+ _default_action = PyString_FromString("default");
+ if (_default_action == NULL)
+ return;
+ Py_INCREF(_default_action);
+ if (PyModule_AddObject(m, "default_action", _default_action) < 0)
+ return;
+}
diff --git a/contrib/tools/python/src/Python/asdl.c b/contrib/tools/python/src/Python/asdl.c
new file mode 100644
index 0000000000..c30d7d2059
--- /dev/null
+++ b/contrib/tools/python/src/Python/asdl.c
@@ -0,0 +1,64 @@
+#include "Python.h"
+#include "asdl.h"
+
+asdl_seq *
+asdl_seq_new(int size, PyArena *arena)
+{
+ asdl_seq *seq = NULL;
+ size_t n = (size ? (sizeof(void *) * (size - 1)) : 0);
+
+ /* check size is sane */
+ if (size < 0 || size == INT_MIN ||
+ (size && ((size - 1) > (PY_SIZE_MAX / sizeof(void *))))) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ /* check if size can be added safely */
+ if (n > PY_SIZE_MAX - sizeof(asdl_seq)) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ n += sizeof(asdl_seq);
+
+ seq = (asdl_seq *)PyArena_Malloc(arena, n);
+ if (!seq) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset(seq, 0, n);
+ seq->size = size;
+ return seq;
+}
+
+asdl_int_seq *
+asdl_int_seq_new(int size, PyArena *arena)
+{
+ asdl_int_seq *seq = NULL;
+ size_t n = (size ? (sizeof(void *) * (size - 1)) : 0);
+
+ /* check size is sane */
+ if (size < 0 || size == INT_MIN ||
+ (size && ((size - 1) > (PY_SIZE_MAX / sizeof(void *))))) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ /* check if size can be added safely */
+ if (n > PY_SIZE_MAX - sizeof(asdl_seq)) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ n += sizeof(asdl_seq);
+
+ seq = (asdl_int_seq *)PyArena_Malloc(arena, n);
+ if (!seq) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset(seq, 0, n);
+ seq->size = size;
+ return seq;
+}
diff --git a/contrib/tools/python/src/Python/ast.c b/contrib/tools/python/src/Python/ast.c
new file mode 100644
index 0000000000..946032589f
--- /dev/null
+++ b/contrib/tools/python/src/Python/ast.c
@@ -0,0 +1,3589 @@
+/*
+ * This file includes functions to transform a concrete syntax tree (CST) to
+ * an abstract syntax tree (AST). The main function is PyAST_FromNode().
+ *
+ */
+#include "Python.h"
+#include "Python-ast.h"
+#include "grammar.h"
+#include "node.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "token.h"
+#include "parsetok.h"
+#include "graminit.h"
+
+#include <assert.h>
+
+/* Data structure used internally */
+struct compiling {
+ char *c_encoding; /* source encoding */
+ int c_future_unicode; /* __future__ unicode literals flag */
+ PyArena *c_arena; /* arena for allocating memeory */
+ const char *c_filename; /* filename */
+};
+
+static asdl_seq *seq_for_testlist(struct compiling *, const node *);
+static expr_ty ast_for_expr(struct compiling *, const node *);
+static stmt_ty ast_for_stmt(struct compiling *, const node *);
+static asdl_seq *ast_for_suite(struct compiling *, const node *);
+static asdl_seq *ast_for_exprlist(struct compiling *, const node *,
+ expr_context_ty);
+static expr_ty ast_for_testlist(struct compiling *, const node *);
+static stmt_ty ast_for_classdef(struct compiling *, const node *, asdl_seq *);
+static expr_ty ast_for_testlist_comp(struct compiling *, const node *);
+
+/* Note different signature for ast_for_call */
+static expr_ty ast_for_call(struct compiling *, const node *, expr_ty);
+
+static PyObject *parsenumber(struct compiling *, const char *);
+static PyObject *parsestr(struct compiling *, const node *n, const char *);
+static PyObject *parsestrplus(struct compiling *, const node *n);
+
+#ifndef LINENO
+#define LINENO(n) ((n)->n_lineno)
+#endif
+
+#define COMP_GENEXP 0
+#define COMP_SETCOMP 1
+
+static identifier
+new_identifier(const char* n, PyArena *arena) {
+ PyObject* id = PyString_InternFromString(n);
+ if (id != NULL)
+ PyArena_AddPyObject(arena, id);
+ return id;
+}
+
+#define NEW_IDENTIFIER(n) new_identifier(STR(n), c->c_arena)
+
+/* This routine provides an invalid object for the syntax error.
+ The outermost routine must unpack this error and create the
+ proper object. We do this so that we don't have to pass
+ the filename to everything function.
+
+ XXX Maybe we should just pass the filename...
+*/
+
+static int
+ast_error(const node *n, const char *errstr)
+{
+ PyObject *u = Py_BuildValue("zi", errstr, LINENO(n));
+ if (!u)
+ return 0;
+ PyErr_SetObject(PyExc_SyntaxError, u);
+ Py_DECREF(u);
+ return 0;
+}
+
+static void
+ast_error_finish(const char *filename)
+{
+ PyObject *type, *value, *tback, *errstr, *loc, *tmp;
+ long lineno;
+
+ assert(PyErr_Occurred());
+ if (!PyErr_ExceptionMatches(PyExc_SyntaxError))
+ return;
+
+ PyErr_Fetch(&type, &value, &tback);
+ errstr = PyTuple_GetItem(value, 0);
+ if (!errstr)
+ return;
+ Py_INCREF(errstr);
+ lineno = PyInt_AsLong(PyTuple_GetItem(value, 1));
+ if (lineno == -1) {
+ Py_DECREF(errstr);
+ return;
+ }
+ Py_DECREF(value);
+
+ loc = PyErr_ProgramText(filename, lineno);
+ if (!loc) {
+ Py_INCREF(Py_None);
+ loc = Py_None;
+ }
+ tmp = Py_BuildValue("(zlOO)", filename, lineno, Py_None, loc);
+ Py_DECREF(loc);
+ if (!tmp) {
+ Py_DECREF(errstr);
+ return;
+ }
+ value = PyTuple_Pack(2, errstr, tmp);
+ Py_DECREF(errstr);
+ Py_DECREF(tmp);
+ if (!value)
+ return;
+ PyErr_Restore(type, value, tback);
+}
+
+static int
+ast_warn(struct compiling *c, const node *n, char *msg)
+{
+ if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, c->c_filename, LINENO(n),
+ NULL, NULL) < 0) {
+ /* if -Werr, change it to a SyntaxError */
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SyntaxWarning))
+ ast_error(n, msg);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+forbidden_check(struct compiling *c, const node *n, const char *x)
+{
+ if (!strcmp(x, "None"))
+ return ast_error(n, "cannot assign to None");
+ if (!strcmp(x, "__debug__"))
+ return ast_error(n, "cannot assign to __debug__");
+ if (Py_Py3kWarningFlag) {
+ if (!(strcmp(x, "True") && strcmp(x, "False")) &&
+ !ast_warn(c, n, "assignment to True or False is forbidden in 3.x"))
+ return 0;
+ if (!strcmp(x, "nonlocal") &&
+ !ast_warn(c, n, "nonlocal is a keyword in 3.x"))
+ return 0;
+ }
+ return 1;
+}
+
+/* num_stmts() returns number of contained statements.
+
+ Use this routine to determine how big a sequence is needed for
+ the statements in a parse tree. Its raison d'etre is this bit of
+ grammar:
+
+ stmt: simple_stmt | compound_stmt
+ simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
+
+ A simple_stmt can contain multiple small_stmt elements joined
+ by semicolons. If the arg is a simple_stmt, the number of
+ small_stmt elements is returned.
+*/
+
+static int
+num_stmts(const node *n)
+{
+ int i, l;
+ node *ch;
+
+ switch (TYPE(n)) {
+ case single_input:
+ if (TYPE(CHILD(n, 0)) == NEWLINE)
+ return 0;
+ else
+ return num_stmts(CHILD(n, 0));
+ case file_input:
+ l = 0;
+ for (i = 0; i < NCH(n); i++) {
+ ch = CHILD(n, i);
+ if (TYPE(ch) == stmt)
+ l += num_stmts(ch);
+ }
+ return l;
+ case stmt:
+ return num_stmts(CHILD(n, 0));
+ case compound_stmt:
+ return 1;
+ case simple_stmt:
+ return NCH(n) / 2; /* Divide by 2 to remove count of semi-colons */
+ case suite:
+ if (NCH(n) == 1)
+ return num_stmts(CHILD(n, 0));
+ else {
+ l = 0;
+ for (i = 2; i < (NCH(n) - 1); i++)
+ l += num_stmts(CHILD(n, i));
+ return l;
+ }
+ default: {
+ char buf[128];
+
+ sprintf(buf, "Non-statement found: %d %d",
+ TYPE(n), NCH(n));
+ Py_FatalError(buf);
+ }
+ }
+ assert(0);
+ return 0;
+}
+
+/* Transform the CST rooted at node * to the appropriate AST
+*/
+
+mod_ty
+PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename,
+ PyArena *arena)
+{
+ int i, j, k, num;
+ asdl_seq *stmts = NULL;
+ stmt_ty s;
+ node *ch;
+ struct compiling c;
+
+ if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) {
+ c.c_encoding = "utf-8";
+ if (TYPE(n) == encoding_decl) {
+ ast_error(n, "encoding declaration in Unicode string");
+ goto error;
+ }
+ } else if (TYPE(n) == encoding_decl) {
+ c.c_encoding = STR(n);
+ n = CHILD(n, 0);
+ } else {
+ c.c_encoding = NULL;
+ }
+ c.c_future_unicode = flags && flags->cf_flags & CO_FUTURE_UNICODE_LITERALS;
+ c.c_arena = arena;
+ c.c_filename = filename;
+
+ k = 0;
+ switch (TYPE(n)) {
+ case file_input:
+ stmts = asdl_seq_new(num_stmts(n), arena);
+ if (!stmts)
+ return NULL;
+ for (i = 0; i < NCH(n) - 1; i++) {
+ ch = CHILD(n, i);
+ if (TYPE(ch) == NEWLINE)
+ continue;
+ REQ(ch, stmt);
+ num = num_stmts(ch);
+ if (num == 1) {
+ s = ast_for_stmt(&c, ch);
+ if (!s)
+ goto error;
+ asdl_seq_SET(stmts, k++, s);
+ }
+ else {
+ ch = CHILD(ch, 0);
+ REQ(ch, simple_stmt);
+ for (j = 0; j < num; j++) {
+ s = ast_for_stmt(&c, CHILD(ch, j * 2));
+ if (!s)
+ goto error;
+ asdl_seq_SET(stmts, k++, s);
+ }
+ }
+ }
+ return Module(stmts, arena);
+ case eval_input: {
+ expr_ty testlist_ast;
+
+ /* XXX Why not comp_for here? */
+ testlist_ast = ast_for_testlist(&c, CHILD(n, 0));
+ if (!testlist_ast)
+ goto error;
+ return Expression(testlist_ast, arena);
+ }
+ case single_input:
+ if (TYPE(CHILD(n, 0)) == NEWLINE) {
+ stmts = asdl_seq_new(1, arena);
+ if (!stmts)
+ goto error;
+ asdl_seq_SET(stmts, 0, Pass(n->n_lineno, n->n_col_offset,
+ arena));
+ if (!asdl_seq_GET(stmts, 0))
+ goto error;
+ return Interactive(stmts, arena);
+ }
+ else {
+ n = CHILD(n, 0);
+ num = num_stmts(n);
+ stmts = asdl_seq_new(num, arena);
+ if (!stmts)
+ goto error;
+ if (num == 1) {
+ s = ast_for_stmt(&c, n);
+ if (!s)
+ goto error;
+ asdl_seq_SET(stmts, 0, s);
+ }
+ else {
+ /* Only a simple_stmt can contain multiple statements. */
+ REQ(n, simple_stmt);
+ for (i = 0; i < NCH(n); i += 2) {
+ if (TYPE(CHILD(n, i)) == NEWLINE)
+ break;
+ s = ast_for_stmt(&c, CHILD(n, i));
+ if (!s)
+ goto error;
+ asdl_seq_SET(stmts, i / 2, s);
+ }
+ }
+
+ return Interactive(stmts, arena);
+ }
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "invalid node %d for PyAST_FromNode", TYPE(n));
+ goto error;
+ }
+ error:
+ ast_error_finish(filename);
+ return NULL;
+}
+
+/* Return the AST repr. of the operator represented as syntax (|, ^, etc.)
+*/
+
+static operator_ty
+get_operator(const node *n)
+{
+ switch (TYPE(n)) {
+ case VBAR:
+ return BitOr;
+ case CIRCUMFLEX:
+ return BitXor;
+ case AMPER:
+ return BitAnd;
+ case LEFTSHIFT:
+ return LShift;
+ case RIGHTSHIFT:
+ return RShift;
+ case PLUS:
+ return Add;
+ case MINUS:
+ return Sub;
+ case STAR:
+ return Mult;
+ case SLASH:
+ return Div;
+ case DOUBLESLASH:
+ return FloorDiv;
+ case PERCENT:
+ return Mod;
+ default:
+ return (operator_ty)0;
+ }
+}
+
+/* Set the context ctx for expr_ty e, recursively traversing e.
+
+ Only sets context for expr kinds that "can appear in assignment context"
+ (according to ../Parser/Python.asdl). For other expr kinds, it sets
+ an appropriate syntax error and returns false.
+*/
+
+static int
+set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
+{
+ asdl_seq *s = NULL;
+ /* If a particular expression type can't be used for assign / delete,
+ set expr_name to its name and an error message will be generated.
+ */
+ const char* expr_name = NULL;
+
+ /* The ast defines augmented store and load contexts, but the
+ implementation here doesn't actually use them. The code may be
+ a little more complex than necessary as a result. It also means
+ that expressions in an augmented assignment have a Store context.
+ Consider restructuring so that augmented assignment uses
+ set_context(), too.
+ */
+ assert(ctx != AugStore && ctx != AugLoad);
+
+ switch (e->kind) {
+ case Attribute_kind:
+ if (ctx == Store && !forbidden_check(c, n,
+ PyBytes_AS_STRING(e->v.Attribute.attr)))
+ return 0;
+ e->v.Attribute.ctx = ctx;
+ break;
+ case Subscript_kind:
+ e->v.Subscript.ctx = ctx;
+ break;
+ case Name_kind:
+ if (ctx == Store && !forbidden_check(c, n,
+ PyBytes_AS_STRING(e->v.Name.id)))
+ return 0;
+ e->v.Name.ctx = ctx;
+ break;
+ case List_kind:
+ e->v.List.ctx = ctx;
+ s = e->v.List.elts;
+ break;
+ case Tuple_kind:
+ if (asdl_seq_LEN(e->v.Tuple.elts)) {
+ e->v.Tuple.ctx = ctx;
+ s = e->v.Tuple.elts;
+ }
+ else {
+ expr_name = "()";
+ }
+ break;
+ case Lambda_kind:
+ expr_name = "lambda";
+ break;
+ case Call_kind:
+ expr_name = "function call";
+ break;
+ case BoolOp_kind:
+ case BinOp_kind:
+ case UnaryOp_kind:
+ expr_name = "operator";
+ break;
+ case GeneratorExp_kind:
+ expr_name = "generator expression";
+ break;
+ case Yield_kind:
+ expr_name = "yield expression";
+ break;
+ case ListComp_kind:
+ expr_name = "list comprehension";
+ break;
+ case SetComp_kind:
+ expr_name = "set comprehension";
+ break;
+ case DictComp_kind:
+ expr_name = "dict comprehension";
+ break;
+ case Dict_kind:
+ case Set_kind:
+ case Num_kind:
+ case Str_kind:
+ expr_name = "literal";
+ break;
+ case Compare_kind:
+ expr_name = "comparison";
+ break;
+ case Repr_kind:
+ expr_name = "repr";
+ break;
+ case IfExp_kind:
+ expr_name = "conditional expression";
+ break;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unexpected expression in assignment %d (line %d)",
+ e->kind, e->lineno);
+ return 0;
+ }
+ /* Check for error string set by switch */
+ if (expr_name) {
+ char buf[300];
+ PyOS_snprintf(buf, sizeof(buf),
+ "can't %s %s",
+ ctx == Store ? "assign to" : "delete",
+ expr_name);
+ return ast_error(n, buf);
+ }
+
+ /* If the LHS is a list or tuple, we need to set the assignment
+ context for all the contained elements.
+ */
+ if (s) {
+ int i;
+
+ for (i = 0; i < asdl_seq_LEN(s); i++) {
+ if (!set_context(c, (expr_ty)asdl_seq_GET(s, i), ctx, n))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static operator_ty
+ast_for_augassign(struct compiling *c, const node *n)
+{
+ REQ(n, augassign);
+ n = CHILD(n, 0);
+ switch (STR(n)[0]) {
+ case '+':
+ return Add;
+ case '-':
+ return Sub;
+ case '/':
+ if (STR(n)[1] == '/')
+ return FloorDiv;
+ else
+ return Div;
+ case '%':
+ return Mod;
+ case '<':
+ return LShift;
+ case '>':
+ return RShift;
+ case '&':
+ return BitAnd;
+ case '^':
+ return BitXor;
+ case '|':
+ return BitOr;
+ case '*':
+ if (STR(n)[1] == '*')
+ return Pow;
+ else
+ return Mult;
+ default:
+ PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n));
+ return (operator_ty)0;
+ }
+}
+
+static cmpop_ty
+ast_for_comp_op(struct compiling *c, const node *n)
+{
+ /* comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'
+ |'is' 'not'
+ */
+ REQ(n, comp_op);
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ switch (TYPE(n)) {
+ case LESS:
+ return Lt;
+ case GREATER:
+ return Gt;
+ case EQEQUAL: /* == */
+ return Eq;
+ case LESSEQUAL:
+ return LtE;
+ case GREATEREQUAL:
+ return GtE;
+ case NOTEQUAL:
+ return NotEq;
+ case NAME:
+ if (strcmp(STR(n), "in") == 0)
+ return In;
+ if (strcmp(STR(n), "is") == 0)
+ return Is;
+ default:
+ PyErr_Format(PyExc_SystemError, "invalid comp_op: %s",
+ STR(n));
+ return (cmpop_ty)0;
+ }
+ }
+ else if (NCH(n) == 2) {
+ /* handle "not in" and "is not" */
+ switch (TYPE(CHILD(n, 0))) {
+ case NAME:
+ if (strcmp(STR(CHILD(n, 1)), "in") == 0)
+ return NotIn;
+ if (strcmp(STR(CHILD(n, 0)), "is") == 0)
+ return IsNot;
+ default:
+ PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s",
+ STR(CHILD(n, 0)), STR(CHILD(n, 1)));
+ return (cmpop_ty)0;
+ }
+ }
+ PyErr_Format(PyExc_SystemError, "invalid comp_op: has %d children",
+ NCH(n));
+ return (cmpop_ty)0;
+}
+
+static asdl_seq *
+seq_for_testlist(struct compiling *c, const node *n)
+{
+ /* testlist: test (',' test)* [','] */
+ asdl_seq *seq;
+ expr_ty expression;
+ int i;
+ assert(TYPE(n) == testlist ||
+ TYPE(n) == listmaker ||
+ TYPE(n) == testlist_comp ||
+ TYPE(n) == testlist_safe ||
+ TYPE(n) == testlist1);
+
+ seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
+ if (!seq)
+ return NULL;
+
+ for (i = 0; i < NCH(n); i += 2) {
+ assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test);
+
+ expression = ast_for_expr(c, CHILD(n, i));
+ if (!expression)
+ return NULL;
+
+ assert(i / 2 < seq->size);
+ asdl_seq_SET(seq, i / 2, expression);
+ }
+ return seq;
+}
+
+static expr_ty
+compiler_complex_args(struct compiling *c, const node *n)
+{
+ int i, len = (NCH(n) + 1) / 2;
+ expr_ty result;
+ asdl_seq *args = asdl_seq_new(len, c->c_arena);
+ if (!args)
+ return NULL;
+
+ /* fpdef: NAME | '(' fplist ')'
+ fplist: fpdef (',' fpdef)* [',']
+ */
+ REQ(n, fplist);
+ for (i = 0; i < len; i++) {
+ PyObject *arg_id;
+ const node *fpdef_node = CHILD(n, 2*i);
+ const node *child;
+ expr_ty arg;
+set_name:
+ /* fpdef_node is either a NAME or an fplist */
+ child = CHILD(fpdef_node, 0);
+ if (TYPE(child) == NAME) {
+ if (!forbidden_check(c, n, STR(child)))
+ return NULL;
+ arg_id = NEW_IDENTIFIER(child);
+ if (!arg_id)
+ return NULL;
+ arg = Name(arg_id, Store, LINENO(child), child->n_col_offset,
+ c->c_arena);
+ }
+ else {
+ assert(TYPE(fpdef_node) == fpdef);
+ /* fpdef_node[0] is not a name, so it must be '(', get CHILD[1] */
+ child = CHILD(fpdef_node, 1);
+ assert(TYPE(child) == fplist);
+ /* NCH == 1 means we have (x), we need to elide the extra parens */
+ if (NCH(child) == 1) {
+ fpdef_node = CHILD(child, 0);
+ assert(TYPE(fpdef_node) == fpdef);
+ goto set_name;
+ }
+ arg = compiler_complex_args(c, child);
+ }
+ asdl_seq_SET(args, i, arg);
+ }
+
+ result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena);
+ if (!set_context(c, result, Store, n))
+ return NULL;
+ return result;
+}
+
+
+/* Create AST for argument list. */
+
+static arguments_ty
+ast_for_arguments(struct compiling *c, const node *n)
+{
+ /* parameters: '(' [varargslist] ')'
+ varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME]
+ | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+ */
+ int i, j, k, n_args = 0, n_defaults = 0, found_default = 0;
+ asdl_seq *args, *defaults;
+ identifier vararg = NULL, kwarg = NULL;
+ node *ch;
+
+ if (TYPE(n) == parameters) {
+ if (NCH(n) == 2) /* () as argument list */
+ return arguments(NULL, NULL, NULL, NULL, c->c_arena);
+ n = CHILD(n, 1);
+ }
+ REQ(n, varargslist);
+
+ /* first count the number of normal args & defaults */
+ for (i = 0; i < NCH(n); i++) {
+ ch = CHILD(n, i);
+ if (TYPE(ch) == fpdef)
+ n_args++;
+ if (TYPE(ch) == EQUAL)
+ n_defaults++;
+ }
+ args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL);
+ if (!args && n_args)
+ return NULL;
+ defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL);
+ if (!defaults && n_defaults)
+ return NULL;
+
+ /* fpdef: NAME | '(' fplist ')'
+ fplist: fpdef (',' fpdef)* [',']
+ */
+ i = 0;
+ j = 0; /* index for defaults */
+ k = 0; /* index for args */
+ while (i < NCH(n)) {
+ ch = CHILD(n, i);
+ switch (TYPE(ch)) {
+ case fpdef: {
+ int complex_args = 0, parenthesized = 0;
+ handle_fpdef:
+ /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is
+ anything other than EQUAL or a comma? */
+ /* XXX Should NCH(n) check be made a separate check? */
+ if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) {
+ expr_ty expression = ast_for_expr(c, CHILD(n, i + 2));
+ if (!expression)
+ return NULL;
+ assert(defaults != NULL);
+ asdl_seq_SET(defaults, j++, expression);
+ i += 2;
+ found_default = 1;
+ }
+ else if (found_default) {
+ /* def f((x)=4): pass should raise an error.
+ def f((x, (y))): pass will just incur the tuple unpacking warning. */
+ if (parenthesized && !complex_args) {
+ ast_error(n, "parenthesized arg with default");
+ return NULL;
+ }
+ ast_error(n,
+ "non-default argument follows default argument");
+ return NULL;
+ }
+ if (NCH(ch) == 3) {
+ ch = CHILD(ch, 1);
+ /* def foo((x)): is not complex, special case. */
+ if (NCH(ch) != 1) {
+ /* We have complex arguments, setup for unpacking. */
+ if (Py_Py3kWarningFlag && !ast_warn(c, ch,
+ "tuple parameter unpacking has been removed in 3.x"))
+ return NULL;
+ complex_args = 1;
+ asdl_seq_SET(args, k++, compiler_complex_args(c, ch));
+ if (!asdl_seq_GET(args, k-1))
+ return NULL;
+ } else {
+ /* def foo((x)): setup for checking NAME below. */
+ /* Loop because there can be many parens and tuple
+ unpacking mixed in. */
+ parenthesized = 1;
+ ch = CHILD(ch, 0);
+ assert(TYPE(ch) == fpdef);
+ goto handle_fpdef;
+ }
+ }
+ if (TYPE(CHILD(ch, 0)) == NAME) {
+ PyObject *id;
+ expr_ty name;
+ if (!forbidden_check(c, n, STR(CHILD(ch, 0))))
+ return NULL;
+ id = NEW_IDENTIFIER(CHILD(ch, 0));
+ if (!id)
+ return NULL;
+ name = Name(id, Param, LINENO(ch), ch->n_col_offset,
+ c->c_arena);
+ if (!name)
+ return NULL;
+ asdl_seq_SET(args, k++, name);
+
+ }
+ i += 2; /* the name and the comma */
+ if (parenthesized && Py_Py3kWarningFlag &&
+ !ast_warn(c, ch, "parenthesized argument names "
+ "are invalid in 3.x"))
+ return NULL;
+
+ break;
+ }
+ case STAR:
+ if (!forbidden_check(c, CHILD(n, i+1), STR(CHILD(n, i+1))))
+ return NULL;
+ vararg = NEW_IDENTIFIER(CHILD(n, i+1));
+ if (!vararg)
+ return NULL;
+ i += 3;
+ break;
+ case DOUBLESTAR:
+ if (!forbidden_check(c, CHILD(n, i+1), STR(CHILD(n, i+1))))
+ return NULL;
+ kwarg = NEW_IDENTIFIER(CHILD(n, i+1));
+ if (!kwarg)
+ return NULL;
+ i += 3;
+ break;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unexpected node in varargslist: %d @ %d",
+ TYPE(ch), i);
+ return NULL;
+ }
+ }
+
+ return arguments(args, vararg, kwarg, defaults, c->c_arena);
+}
+
+static expr_ty
+ast_for_dotted_name(struct compiling *c, const node *n)
+{
+ expr_ty e;
+ identifier id;
+ int lineno, col_offset;
+ int i;
+
+ REQ(n, dotted_name);
+
+ lineno = LINENO(n);
+ col_offset = n->n_col_offset;
+
+ id = NEW_IDENTIFIER(CHILD(n, 0));
+ if (!id)
+ return NULL;
+ e = Name(id, Load, lineno, col_offset, c->c_arena);
+ if (!e)
+ return NULL;
+
+ for (i = 2; i < NCH(n); i+=2) {
+ id = NEW_IDENTIFIER(CHILD(n, i));
+ if (!id)
+ return NULL;
+ e = Attribute(e, id, Load, lineno, col_offset, c->c_arena);
+ if (!e)
+ return NULL;
+ }
+
+ return e;
+}
+
+static expr_ty
+ast_for_decorator(struct compiling *c, const node *n)
+{
+ /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */
+ expr_ty d = NULL;
+ expr_ty name_expr;
+
+ REQ(n, decorator);
+ REQ(CHILD(n, 0), AT);
+ REQ(RCHILD(n, -1), NEWLINE);
+
+ name_expr = ast_for_dotted_name(c, CHILD(n, 1));
+ if (!name_expr)
+ return NULL;
+
+ if (NCH(n) == 3) { /* No arguments */
+ d = name_expr;
+ name_expr = NULL;
+ }
+ else if (NCH(n) == 5) { /* Call with no arguments */
+ d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ if (!d)
+ return NULL;
+ name_expr = NULL;
+ }
+ else {
+ d = ast_for_call(c, CHILD(n, 3), name_expr);
+ if (!d)
+ return NULL;
+ name_expr = NULL;
+ }
+
+ return d;
+}
+
+static asdl_seq*
+ast_for_decorators(struct compiling *c, const node *n)
+{
+ asdl_seq* decorator_seq;
+ expr_ty d;
+ int i;
+
+ REQ(n, decorators);
+ decorator_seq = asdl_seq_new(NCH(n), c->c_arena);
+ if (!decorator_seq)
+ return NULL;
+
+ for (i = 0; i < NCH(n); i++) {
+ d = ast_for_decorator(c, CHILD(n, i));
+ if (!d)
+ return NULL;
+ asdl_seq_SET(decorator_seq, i, d);
+ }
+ return decorator_seq;
+}
+
+static stmt_ty
+ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
+{
+ /* funcdef: 'def' NAME parameters ':' suite */
+ identifier name;
+ arguments_ty args;
+ asdl_seq *body;
+ int name_i = 1;
+
+ REQ(n, funcdef);
+
+ name = NEW_IDENTIFIER(CHILD(n, name_i));
+ if (!name)
+ return NULL;
+ else if (!forbidden_check(c, CHILD(n, name_i), STR(CHILD(n, name_i))))
+ return NULL;
+ args = ast_for_arguments(c, CHILD(n, name_i + 1));
+ if (!args)
+ return NULL;
+ body = ast_for_suite(c, CHILD(n, name_i + 3));
+ if (!body)
+ return NULL;
+
+ return FunctionDef(name, args, body, decorator_seq, LINENO(n),
+ n->n_col_offset, c->c_arena);
+}
+
+static stmt_ty
+ast_for_decorated(struct compiling *c, const node *n)
+{
+ /* decorated: decorators (classdef | funcdef) */
+ stmt_ty thing = NULL;
+ asdl_seq *decorator_seq = NULL;
+
+ REQ(n, decorated);
+
+ decorator_seq = ast_for_decorators(c, CHILD(n, 0));
+ if (!decorator_seq)
+ return NULL;
+
+ assert(TYPE(CHILD(n, 1)) == funcdef ||
+ TYPE(CHILD(n, 1)) == classdef);
+
+ if (TYPE(CHILD(n, 1)) == funcdef) {
+ thing = ast_for_funcdef(c, CHILD(n, 1), decorator_seq);
+ } else if (TYPE(CHILD(n, 1)) == classdef) {
+ thing = ast_for_classdef(c, CHILD(n, 1), decorator_seq);
+ }
+ /* we count the decorators in when talking about the class' or
+ function's line number */
+ if (thing) {
+ thing->lineno = LINENO(n);
+ thing->col_offset = n->n_col_offset;
+ }
+ return thing;
+}
+
+static expr_ty
+ast_for_lambdef(struct compiling *c, const node *n)
+{
+ /* lambdef: 'lambda' [varargslist] ':' test */
+ arguments_ty args;
+ expr_ty expression;
+
+ if (NCH(n) == 3) {
+ args = arguments(NULL, NULL, NULL, NULL, c->c_arena);
+ if (!args)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, 2));
+ if (!expression)
+ return NULL;
+ }
+ else {
+ args = ast_for_arguments(c, CHILD(n, 1));
+ if (!args)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, 3));
+ if (!expression)
+ return NULL;
+ }
+
+ return Lambda(args, expression, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static expr_ty
+ast_for_ifexpr(struct compiling *c, const node *n)
+{
+ /* test: or_test 'if' or_test 'else' test */
+ expr_ty expression, body, orelse;
+
+ assert(NCH(n) == 5);
+ body = ast_for_expr(c, CHILD(n, 0));
+ if (!body)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, 2));
+ if (!expression)
+ return NULL;
+ orelse = ast_for_expr(c, CHILD(n, 4));
+ if (!orelse)
+ return NULL;
+ return IfExp(expression, body, orelse, LINENO(n), n->n_col_offset,
+ c->c_arena);
+}
+
+/* XXX(nnorwitz): the listcomp and genexpr code should be refactored
+ so there is only a single version. Possibly for loops can also re-use
+ the code.
+*/
+
+/* Count the number of 'for' loop in a list comprehension.
+
+ Helper for ast_for_listcomp().
+*/
+
+static int
+count_list_fors(struct compiling *c, const node *n)
+{
+ int n_fors = 0;
+ node *ch = CHILD(n, 1);
+
+ count_list_for:
+ n_fors++;
+ REQ(ch, list_for);
+ if (NCH(ch) == 5)
+ ch = CHILD(ch, 4);
+ else
+ return n_fors;
+ count_list_iter:
+ REQ(ch, list_iter);
+ ch = CHILD(ch, 0);
+ if (TYPE(ch) == list_for)
+ goto count_list_for;
+ else if (TYPE(ch) == list_if) {
+ if (NCH(ch) == 3) {
+ ch = CHILD(ch, 2);
+ goto count_list_iter;
+ }
+ else
+ return n_fors;
+ }
+
+ /* Should never be reached */
+ PyErr_SetString(PyExc_SystemError, "logic error in count_list_fors");
+ return -1;
+}
+
+/* Count the number of 'if' statements in a list comprehension.
+
+ Helper for ast_for_listcomp().
+*/
+
+static int
+count_list_ifs(struct compiling *c, const node *n)
+{
+ int n_ifs = 0;
+
+ count_list_iter:
+ REQ(n, list_iter);
+ if (TYPE(CHILD(n, 0)) == list_for)
+ return n_ifs;
+ n = CHILD(n, 0);
+ REQ(n, list_if);
+ n_ifs++;
+ if (NCH(n) == 2)
+ return n_ifs;
+ n = CHILD(n, 2);
+ goto count_list_iter;
+}
+
+static expr_ty
+ast_for_listcomp(struct compiling *c, const node *n)
+{
+ /* listmaker: test ( list_for | (',' test)* [','] )
+ list_for: 'for' exprlist 'in' testlist_safe [list_iter]
+ list_iter: list_for | list_if
+ list_if: 'if' test [list_iter]
+ testlist_safe: test [(',' test)+ [',']]
+ */
+ expr_ty elt, first;
+ asdl_seq *listcomps;
+ int i, n_fors;
+ node *ch;
+
+ REQ(n, listmaker);
+ assert(NCH(n) > 1);
+
+ elt = ast_for_expr(c, CHILD(n, 0));
+ if (!elt)
+ return NULL;
+
+ n_fors = count_list_fors(c, n);
+ if (n_fors == -1)
+ return NULL;
+
+ listcomps = asdl_seq_new(n_fors, c->c_arena);
+ if (!listcomps)
+ return NULL;
+
+ ch = CHILD(n, 1);
+ for (i = 0; i < n_fors; i++) {
+ comprehension_ty lc;
+ asdl_seq *t;
+ expr_ty expression;
+ node *for_ch;
+
+ REQ(ch, list_for);
+
+ for_ch = CHILD(ch, 1);
+ t = ast_for_exprlist(c, for_ch, Store);
+ if (!t)
+ return NULL;
+ expression = ast_for_testlist(c, CHILD(ch, 3));
+ if (!expression)
+ return NULL;
+
+ /* Check the # of children rather than the length of t, since
+ [x for x, in ... ] has 1 element in t, but still requires a Tuple.
+ */
+ first = (expr_ty)asdl_seq_GET(t, 0);
+ if (NCH(for_ch) == 1)
+ lc = comprehension(first, expression, NULL, c->c_arena);
+ else
+ lc = comprehension(Tuple(t, Store, first->lineno, first->col_offset,
+ c->c_arena),
+ expression, NULL, c->c_arena);
+ if (!lc)
+ return NULL;
+
+ if (NCH(ch) == 5) {
+ int j, n_ifs;
+ asdl_seq *ifs;
+ expr_ty list_for_expr;
+
+ ch = CHILD(ch, 4);
+ n_ifs = count_list_ifs(c, ch);
+ if (n_ifs == -1)
+ return NULL;
+
+ ifs = asdl_seq_new(n_ifs, c->c_arena);
+ if (!ifs)
+ return NULL;
+
+ for (j = 0; j < n_ifs; j++) {
+ REQ(ch, list_iter);
+ ch = CHILD(ch, 0);
+ REQ(ch, list_if);
+
+ list_for_expr = ast_for_expr(c, CHILD(ch, 1));
+ if (!list_for_expr)
+ return NULL;
+
+ asdl_seq_SET(ifs, j, list_for_expr);
+ if (NCH(ch) == 3)
+ ch = CHILD(ch, 2);
+ }
+ /* on exit, must guarantee that ch is a list_for */
+ if (TYPE(ch) == list_iter)
+ ch = CHILD(ch, 0);
+ lc->ifs = ifs;
+ }
+ asdl_seq_SET(listcomps, i, lc);
+ }
+
+ return ListComp(elt, listcomps, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+/*
+ Count the number of 'for' loops in a comprehension.
+
+ Helper for ast_for_comprehension().
+*/
+
+static int
+count_comp_fors(struct compiling *c, const node *n)
+{
+ int n_fors = 0;
+
+ count_comp_for:
+ n_fors++;
+ REQ(n, comp_for);
+ if (NCH(n) == 5)
+ n = CHILD(n, 4);
+ else
+ return n_fors;
+ count_comp_iter:
+ REQ(n, comp_iter);
+ n = CHILD(n, 0);
+ if (TYPE(n) == comp_for)
+ goto count_comp_for;
+ else if (TYPE(n) == comp_if) {
+ if (NCH(n) == 3) {
+ n = CHILD(n, 2);
+ goto count_comp_iter;
+ }
+ else
+ return n_fors;
+ }
+
+ /* Should never be reached */
+ PyErr_SetString(PyExc_SystemError,
+ "logic error in count_comp_fors");
+ return -1;
+}
+
+/* Count the number of 'if' statements in a comprehension.
+
+ Helper for ast_for_comprehension().
+*/
+
+static int
+count_comp_ifs(struct compiling *c, const node *n)
+{
+ int n_ifs = 0;
+
+ while (1) {
+ REQ(n, comp_iter);
+ if (TYPE(CHILD(n, 0)) == comp_for)
+ return n_ifs;
+ n = CHILD(n, 0);
+ REQ(n, comp_if);
+ n_ifs++;
+ if (NCH(n) == 2)
+ return n_ifs;
+ n = CHILD(n, 2);
+ }
+}
+
+static asdl_seq *
+ast_for_comprehension(struct compiling *c, const node *n)
+{
+ int i, n_fors;
+ asdl_seq *comps;
+
+ n_fors = count_comp_fors(c, n);
+ if (n_fors == -1)
+ return NULL;
+
+ comps = asdl_seq_new(n_fors, c->c_arena);
+ if (!comps)
+ return NULL;
+
+ for (i = 0; i < n_fors; i++) {
+ comprehension_ty comp;
+ asdl_seq *t;
+ expr_ty expression, first;
+ node *for_ch;
+
+ REQ(n, comp_for);
+
+ for_ch = CHILD(n, 1);
+ t = ast_for_exprlist(c, for_ch, Store);
+ if (!t)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, 3));
+ if (!expression)
+ return NULL;
+
+ /* Check the # of children rather than the length of t, since
+ (x for x, in ...) has 1 element in t, but still requires a Tuple. */
+ first = (expr_ty)asdl_seq_GET(t, 0);
+ if (NCH(for_ch) == 1)
+ comp = comprehension(first, expression, NULL, c->c_arena);
+ else
+ comp = comprehension(Tuple(t, Store, first->lineno, first->col_offset,
+ c->c_arena),
+ expression, NULL, c->c_arena);
+ if (!comp)
+ return NULL;
+
+ if (NCH(n) == 5) {
+ int j, n_ifs;
+ asdl_seq *ifs;
+
+ n = CHILD(n, 4);
+ n_ifs = count_comp_ifs(c, n);
+ if (n_ifs == -1)
+ return NULL;
+
+ ifs = asdl_seq_new(n_ifs, c->c_arena);
+ if (!ifs)
+ return NULL;
+
+ for (j = 0; j < n_ifs; j++) {
+ REQ(n, comp_iter);
+ n = CHILD(n, 0);
+ REQ(n, comp_if);
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ asdl_seq_SET(ifs, j, expression);
+ if (NCH(n) == 3)
+ n = CHILD(n, 2);
+ }
+ /* on exit, must guarantee that n is a comp_for */
+ if (TYPE(n) == comp_iter)
+ n = CHILD(n, 0);
+ comp->ifs = ifs;
+ }
+ asdl_seq_SET(comps, i, comp);
+ }
+ return comps;
+}
+
+static expr_ty
+ast_for_itercomp(struct compiling *c, const node *n, int type)
+{
+ expr_ty elt;
+ asdl_seq *comps;
+
+ assert(NCH(n) > 1);
+
+ elt = ast_for_expr(c, CHILD(n, 0));
+ if (!elt)
+ return NULL;
+
+ comps = ast_for_comprehension(c, CHILD(n, 1));
+ if (!comps)
+ return NULL;
+
+ if (type == COMP_GENEXP)
+ return GeneratorExp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena);
+ else if (type == COMP_SETCOMP)
+ return SetComp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena);
+ else
+ /* Should never happen */
+ return NULL;
+}
+
+static expr_ty
+ast_for_dictcomp(struct compiling *c, const node *n)
+{
+ expr_ty key, value;
+ asdl_seq *comps;
+
+ assert(NCH(n) > 3);
+ REQ(CHILD(n, 1), COLON);
+
+ key = ast_for_expr(c, CHILD(n, 0));
+ if (!key)
+ return NULL;
+
+ value = ast_for_expr(c, CHILD(n, 2));
+ if (!value)
+ return NULL;
+
+ comps = ast_for_comprehension(c, CHILD(n, 3));
+ if (!comps)
+ return NULL;
+
+ return DictComp(key, value, comps, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static expr_ty
+ast_for_genexp(struct compiling *c, const node *n)
+{
+ assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument));
+ return ast_for_itercomp(c, n, COMP_GENEXP);
+}
+
+static expr_ty
+ast_for_setcomp(struct compiling *c, const node *n)
+{
+ assert(TYPE(n) == (dictorsetmaker));
+ return ast_for_itercomp(c, n, COMP_SETCOMP);
+}
+
+static expr_ty
+ast_for_atom(struct compiling *c, const node *n)
+{
+ /* atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']'
+ | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
+ */
+ node *ch = CHILD(n, 0);
+
+ switch (TYPE(ch)) {
+ case NAME: {
+ /* All names start in Load context, but may later be
+ changed. */
+ PyObject *name = NEW_IDENTIFIER(ch);
+ if (!name)
+ return NULL;
+ return Name(name, Load, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ case STRING: {
+ PyObject *str = parsestrplus(c, n);
+ if (!str) {
+#ifdef Py_USING_UNICODE
+ if (PyErr_ExceptionMatches(PyExc_UnicodeError)){
+ PyObject *type, *value, *tback, *errstr;
+ PyErr_Fetch(&type, &value, &tback);
+ errstr = PyObject_Str(value);
+ if (errstr) {
+ char *s = "";
+ char buf[128];
+ s = PyString_AsString(errstr);
+ PyOS_snprintf(buf, sizeof(buf), "(unicode error) %s", s);
+ ast_error(n, buf);
+ Py_DECREF(errstr);
+ } else {
+ ast_error(n, "(unicode error) unknown error");
+ }
+ Py_DECREF(type);
+ Py_DECREF(value);
+ Py_XDECREF(tback);
+ }
+#endif
+ return NULL;
+ }
+ PyArena_AddPyObject(c->c_arena, str);
+ return Str(str, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ case NUMBER: {
+ PyObject *pynum = parsenumber(c, STR(ch));
+ if (!pynum)
+ return NULL;
+
+ PyArena_AddPyObject(c->c_arena, pynum);
+ return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ case LPAR: /* some parenthesized expressions */
+ ch = CHILD(n, 1);
+
+ if (TYPE(ch) == RPAR)
+ return Tuple(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena);
+
+ if (TYPE(ch) == yield_expr)
+ return ast_for_expr(c, ch);
+
+ return ast_for_testlist_comp(c, ch);
+ case LSQB: /* list (or list comprehension) */
+ ch = CHILD(n, 1);
+
+ if (TYPE(ch) == RSQB)
+ return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena);
+
+ REQ(ch, listmaker);
+ if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) {
+ asdl_seq *elts = seq_for_testlist(c, ch);
+ if (!elts)
+ return NULL;
+
+ return List(elts, Load, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ else
+ return ast_for_listcomp(c, ch);
+ case LBRACE: {
+ /* dictorsetmaker:
+ * (test ':' test (comp_for | (',' test ':' test)* [','])) |
+ * (test (comp_for | (',' test)* [',']))
+ */
+ int i, size;
+ asdl_seq *keys, *values;
+
+ ch = CHILD(n, 1);
+ if (TYPE(ch) == RBRACE) {
+ /* it's an empty dict */
+ return Dict(NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
+ } else if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) {
+ /* it's a simple set */
+ asdl_seq *elts;
+ size = (NCH(ch) + 1) / 2; /* +1 in case no trailing comma */
+ elts = asdl_seq_new(size, c->c_arena);
+ if (!elts)
+ return NULL;
+ for (i = 0; i < NCH(ch); i += 2) {
+ expr_ty expression;
+ expression = ast_for_expr(c, CHILD(ch, i));
+ if (!expression)
+ return NULL;
+ asdl_seq_SET(elts, i / 2, expression);
+ }
+ return Set(elts, LINENO(n), n->n_col_offset, c->c_arena);
+ } else if (TYPE(CHILD(ch, 1)) == comp_for) {
+ /* it's a set comprehension */
+ return ast_for_setcomp(c, ch);
+ } else if (NCH(ch) > 3 && TYPE(CHILD(ch, 3)) == comp_for) {
+ return ast_for_dictcomp(c, ch);
+ } else {
+ /* it's a dict */
+ size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */
+ keys = asdl_seq_new(size, c->c_arena);
+ if (!keys)
+ return NULL;
+
+ values = asdl_seq_new(size, c->c_arena);
+ if (!values)
+ return NULL;
+
+ for (i = 0; i < NCH(ch); i += 4) {
+ expr_ty expression;
+
+ expression = ast_for_expr(c, CHILD(ch, i));
+ if (!expression)
+ return NULL;
+
+ asdl_seq_SET(keys, i / 4, expression);
+
+ expression = ast_for_expr(c, CHILD(ch, i + 2));
+ if (!expression)
+ return NULL;
+
+ asdl_seq_SET(values, i / 4, expression);
+ }
+ return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ }
+ case BACKQUOTE: { /* repr */
+ expr_ty expression;
+ if (Py_Py3kWarningFlag &&
+ !ast_warn(c, n, "backquote not supported in 3.x; use repr()"))
+ return NULL;
+ expression = ast_for_testlist(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+
+ return Repr(expression, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ default:
+ PyErr_Format(PyExc_SystemError, "unhandled atom %d", TYPE(ch));
+ return NULL;
+ }
+}
+
+static slice_ty
+ast_for_slice(struct compiling *c, const node *n)
+{
+ node *ch;
+ expr_ty lower = NULL, upper = NULL, step = NULL;
+
+ REQ(n, subscript);
+
+ /*
+ subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
+ sliceop: ':' [test]
+ */
+ ch = CHILD(n, 0);
+ if (TYPE(ch) == DOT)
+ return Ellipsis(c->c_arena);
+
+ if (NCH(n) == 1 && TYPE(ch) == test) {
+ /* 'step' variable hold no significance in terms of being used over
+ other vars */
+ step = ast_for_expr(c, ch);
+ if (!step)
+ return NULL;
+
+ return Index(step, c->c_arena);
+ }
+
+ if (TYPE(ch) == test) {
+ lower = ast_for_expr(c, ch);
+ if (!lower)
+ return NULL;
+ }
+
+ /* If there's an upper bound it's in the second or third position. */
+ if (TYPE(ch) == COLON) {
+ if (NCH(n) > 1) {
+ node *n2 = CHILD(n, 1);
+
+ if (TYPE(n2) == test) {
+ upper = ast_for_expr(c, n2);
+ if (!upper)
+ return NULL;
+ }
+ }
+ } else if (NCH(n) > 2) {
+ node *n2 = CHILD(n, 2);
+
+ if (TYPE(n2) == test) {
+ upper = ast_for_expr(c, n2);
+ if (!upper)
+ return NULL;
+ }
+ }
+
+ ch = CHILD(n, NCH(n) - 1);
+ if (TYPE(ch) == sliceop) {
+ if (NCH(ch) == 1) {
+ /*
+ This is an extended slice (ie "x[::]") with no expression in the
+ step field. We set this literally to "None" in order to
+ disambiguate it from x[:]. (The interpreter might have to call
+ __getslice__ for x[:], but it must call __getitem__ for x[::].)
+ */
+ identifier none = new_identifier("None", c->c_arena);
+ if (!none)
+ return NULL;
+ ch = CHILD(ch, 0);
+ step = Name(none, Load, LINENO(ch), ch->n_col_offset, c->c_arena);
+ if (!step)
+ return NULL;
+ } else {
+ ch = CHILD(ch, 1);
+ if (TYPE(ch) == test) {
+ step = ast_for_expr(c, ch);
+ if (!step)
+ return NULL;
+ }
+ }
+ }
+
+ return Slice(lower, upper, step, c->c_arena);
+}
+
+static expr_ty
+ast_for_binop(struct compiling *c, const node *n)
+{
+ /* Must account for a sequence of expressions.
+ How should A op B op C by represented?
+ BinOp(BinOp(A, op, B), op, C).
+ */
+
+ int i, nops;
+ expr_ty expr1, expr2, result;
+ operator_ty newoperator;
+
+ expr1 = ast_for_expr(c, CHILD(n, 0));
+ if (!expr1)
+ return NULL;
+
+ expr2 = ast_for_expr(c, CHILD(n, 2));
+ if (!expr2)
+ return NULL;
+
+ newoperator = get_operator(CHILD(n, 1));
+ if (!newoperator)
+ return NULL;
+
+ result = BinOp(expr1, newoperator, expr2, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ if (!result)
+ return NULL;
+
+ nops = (NCH(n) - 1) / 2;
+ for (i = 1; i < nops; i++) {
+ expr_ty tmp_result, tmp;
+ const node* next_oper = CHILD(n, i * 2 + 1);
+
+ newoperator = get_operator(next_oper);
+ if (!newoperator)
+ return NULL;
+
+ tmp = ast_for_expr(c, CHILD(n, i * 2 + 2));
+ if (!tmp)
+ return NULL;
+
+ tmp_result = BinOp(result, newoperator, tmp,
+ LINENO(next_oper), next_oper->n_col_offset,
+ c->c_arena);
+ if (!tmp_result)
+ return NULL;
+ result = tmp_result;
+ }
+ return result;
+}
+
+static expr_ty
+ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
+{
+ /* trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
+ subscriptlist: subscript (',' subscript)* [',']
+ subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
+ */
+ REQ(n, trailer);
+ if (TYPE(CHILD(n, 0)) == LPAR) {
+ if (NCH(n) == 2)
+ return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ else
+ return ast_for_call(c, CHILD(n, 1), left_expr);
+ }
+ else if (TYPE(CHILD(n, 0)) == DOT ) {
+ PyObject *attr_id = NEW_IDENTIFIER(CHILD(n, 1));
+ if (!attr_id)
+ return NULL;
+ return Attribute(left_expr, attr_id, Load,
+ LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ else {
+ REQ(CHILD(n, 0), LSQB);
+ REQ(CHILD(n, 2), RSQB);
+ n = CHILD(n, 1);
+ if (NCH(n) == 1) {
+ slice_ty slc = ast_for_slice(c, CHILD(n, 0));
+ if (!slc)
+ return NULL;
+ return Subscript(left_expr, slc, Load, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else {
+ /* The grammar is ambiguous here. The ambiguity is resolved
+ by treating the sequence as a tuple literal if there are
+ no slice features.
+ */
+ int j;
+ slice_ty slc;
+ expr_ty e;
+ bool simple = true;
+ asdl_seq *slices, *elts;
+ slices = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
+ if (!slices)
+ return NULL;
+ for (j = 0; j < NCH(n); j += 2) {
+ slc = ast_for_slice(c, CHILD(n, j));
+ if (!slc)
+ return NULL;
+ if (slc->kind != Index_kind)
+ simple = false;
+ asdl_seq_SET(slices, j / 2, slc);
+ }
+ if (!simple) {
+ return Subscript(left_expr, ExtSlice(slices, c->c_arena),
+ Load, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ /* extract Index values and put them in a Tuple */
+ elts = asdl_seq_new(asdl_seq_LEN(slices), c->c_arena);
+ if (!elts)
+ return NULL;
+ for (j = 0; j < asdl_seq_LEN(slices); ++j) {
+ slc = (slice_ty)asdl_seq_GET(slices, j);
+ assert(slc->kind == Index_kind && slc->v.Index.value);
+ asdl_seq_SET(elts, j, slc->v.Index.value);
+ }
+ e = Tuple(elts, Load, LINENO(n), n->n_col_offset, c->c_arena);
+ if (!e)
+ return NULL;
+ return Subscript(left_expr, Index(e, c->c_arena),
+ Load, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ }
+}
+
+static expr_ty
+ast_for_factor(struct compiling *c, const node *n)
+{
+ node *pfactor, *ppower, *patom, *pnum;
+ expr_ty expression;
+
+ /* If the unary - operator is applied to a constant, don't generate
+ a UNARY_NEGATIVE opcode. Just store the approriate value as a
+ constant. The peephole optimizer already does something like
+ this but it doesn't handle the case where the constant is
+ (sys.maxint - 1). In that case, we want a PyIntObject, not a
+ PyLongObject.
+ */
+ if (TYPE(CHILD(n, 0)) == MINUS &&
+ NCH(n) == 2 &&
+ TYPE((pfactor = CHILD(n, 1))) == factor &&
+ NCH(pfactor) == 1 &&
+ TYPE((ppower = CHILD(pfactor, 0))) == power &&
+ NCH(ppower) == 1 &&
+ TYPE((patom = CHILD(ppower, 0))) == atom &&
+ TYPE((pnum = CHILD(patom, 0))) == NUMBER) {
+ PyObject *pynum;
+ char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2);
+ if (s == NULL)
+ return NULL;
+ s[0] = '-';
+ strcpy(s + 1, STR(pnum));
+ pynum = parsenumber(c, s);
+ PyObject_FREE(s);
+ if (!pynum)
+ return NULL;
+
+ PyArena_AddPyObject(c->c_arena, pynum);
+ return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+
+ switch (TYPE(CHILD(n, 0))) {
+ case PLUS:
+ return UnaryOp(UAdd, expression, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ case MINUS:
+ return UnaryOp(USub, expression, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ case TILDE:
+ return UnaryOp(Invert, expression, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ }
+ PyErr_Format(PyExc_SystemError, "unhandled factor: %d",
+ TYPE(CHILD(n, 0)));
+ return NULL;
+}
+
+static expr_ty
+ast_for_power(struct compiling *c, const node *n)
+{
+ /* power: atom trailer* ('**' factor)*
+ */
+ int i;
+ expr_ty e, tmp;
+ REQ(n, power);
+ e = ast_for_atom(c, CHILD(n, 0));
+ if (!e)
+ return NULL;
+ if (NCH(n) == 1)
+ return e;
+ for (i = 1; i < NCH(n); i++) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) != trailer)
+ break;
+ tmp = ast_for_trailer(c, ch, e);
+ if (!tmp)
+ return NULL;
+ tmp->lineno = e->lineno;
+ tmp->col_offset = e->col_offset;
+ e = tmp;
+ }
+ if (TYPE(CHILD(n, NCH(n) - 1)) == factor) {
+ expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1));
+ if (!f)
+ return NULL;
+ tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena);
+ if (!tmp)
+ return NULL;
+ e = tmp;
+ }
+ return e;
+}
+
+/* Do not name a variable 'expr'! Will cause a compile error.
+*/
+
+static expr_ty
+ast_for_expr(struct compiling *c, const node *n)
+{
+ /* handle the full range of simple expressions
+ test: or_test ['if' or_test 'else' test] | lambdef
+ or_test: and_test ('or' and_test)*
+ and_test: not_test ('and' not_test)*
+ not_test: 'not' not_test | comparison
+ comparison: expr (comp_op expr)*
+ expr: xor_expr ('|' xor_expr)*
+ xor_expr: and_expr ('^' and_expr)*
+ and_expr: shift_expr ('&' shift_expr)*
+ shift_expr: arith_expr (('<<'|'>>') arith_expr)*
+ arith_expr: term (('+'|'-') term)*
+ term: factor (('*'|'/'|'%'|'//') factor)*
+ factor: ('+'|'-'|'~') factor | power
+ power: atom trailer* ('**' factor)*
+
+ As well as modified versions that exist for backward compatibility,
+ to explicitly allow:
+ [ x for x in lambda: 0, lambda: 1 ]
+ (which would be ambiguous without these extra rules)
+
+ old_test: or_test | old_lambdef
+ old_lambdef: 'lambda' [vararglist] ':' old_test
+
+ */
+
+ asdl_seq *seq;
+ int i;
+
+ loop:
+ switch (TYPE(n)) {
+ case test:
+ case old_test:
+ if (TYPE(CHILD(n, 0)) == lambdef ||
+ TYPE(CHILD(n, 0)) == old_lambdef)
+ return ast_for_lambdef(c, CHILD(n, 0));
+ else if (NCH(n) > 1)
+ return ast_for_ifexpr(c, n);
+ /* Fallthrough */
+ case or_test:
+ case and_test:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
+ if (!seq)
+ return NULL;
+ for (i = 0; i < NCH(n); i += 2) {
+ expr_ty e = ast_for_expr(c, CHILD(n, i));
+ if (!e)
+ return NULL;
+ asdl_seq_SET(seq, i / 2, e);
+ }
+ if (!strcmp(STR(CHILD(n, 1)), "and"))
+ return BoolOp(And, seq, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ assert(!strcmp(STR(CHILD(n, 1)), "or"));
+ return BoolOp(Or, seq, LINENO(n), n->n_col_offset, c->c_arena);
+ case not_test:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ else {
+ expr_ty expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+
+ return UnaryOp(Not, expression, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ case comparison:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ else {
+ expr_ty expression;
+ asdl_int_seq *ops;
+ asdl_seq *cmps;
+ ops = asdl_int_seq_new(NCH(n) / 2, c->c_arena);
+ if (!ops)
+ return NULL;
+ cmps = asdl_seq_new(NCH(n) / 2, c->c_arena);
+ if (!cmps) {
+ return NULL;
+ }
+ for (i = 1; i < NCH(n); i += 2) {
+ cmpop_ty newoperator;
+
+ newoperator = ast_for_comp_op(c, CHILD(n, i));
+ if (!newoperator) {
+ return NULL;
+ }
+
+ expression = ast_for_expr(c, CHILD(n, i + 1));
+ if (!expression) {
+ return NULL;
+ }
+
+ asdl_seq_SET(ops, i / 2, newoperator);
+ asdl_seq_SET(cmps, i / 2, expression);
+ }
+ expression = ast_for_expr(c, CHILD(n, 0));
+ if (!expression) {
+ return NULL;
+ }
+
+ return Compare(expression, ops, cmps, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ }
+ break;
+
+ /* The next five cases all handle BinOps. The main body of code
+ is the same in each case, but the switch turned inside out to
+ reuse the code for each type of operator.
+ */
+ case expr:
+ case xor_expr:
+ case and_expr:
+ case shift_expr:
+ case arith_expr:
+ case term:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ return ast_for_binop(c, n);
+ case yield_expr: {
+ expr_ty exp = NULL;
+ if (NCH(n) == 2) {
+ exp = ast_for_testlist(c, CHILD(n, 1));
+ if (!exp)
+ return NULL;
+ }
+ return Yield(exp, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ case factor:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ return ast_for_factor(c, n);
+ case power:
+ return ast_for_power(c, n);
+ default:
+ PyErr_Format(PyExc_SystemError, "unhandled expr: %d", TYPE(n));
+ return NULL;
+ }
+ /* should never get here unless if error is set */
+ return NULL;
+}
+
+static expr_ty
+ast_for_call(struct compiling *c, const node *n, expr_ty func)
+{
+ /*
+ arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
+ | '**' test)
+ argument: [test '='] test [comp_for] # Really [keyword '='] test
+ */
+
+ int i, nargs, nkeywords, ngens;
+ asdl_seq *args;
+ asdl_seq *keywords;
+ expr_ty vararg = NULL, kwarg = NULL;
+
+ REQ(n, arglist);
+
+ nargs = 0;
+ nkeywords = 0;
+ ngens = 0;
+ for (i = 0; i < NCH(n); i++) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == argument) {
+ if (NCH(ch) == 1)
+ nargs++;
+ else if (TYPE(CHILD(ch, 1)) == comp_for)
+ ngens++;
+ else
+ nkeywords++;
+ }
+ }
+ if (ngens > 1 || (ngens && (nargs || nkeywords))) {
+ ast_error(n, "Generator expression must be parenthesized "
+ "if not sole argument");
+ return NULL;
+ }
+
+ if (nargs + nkeywords + ngens > 255) {
+ ast_error(n, "more than 255 arguments");
+ return NULL;
+ }
+
+ args = asdl_seq_new(nargs + ngens, c->c_arena);
+ if (!args)
+ return NULL;
+ keywords = asdl_seq_new(nkeywords, c->c_arena);
+ if (!keywords)
+ return NULL;
+ nargs = 0;
+ nkeywords = 0;
+ for (i = 0; i < NCH(n); i++) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == argument) {
+ expr_ty e;
+ if (NCH(ch) == 1) {
+ if (nkeywords) {
+ ast_error(CHILD(ch, 0),
+ "non-keyword arg after keyword arg");
+ return NULL;
+ }
+ if (vararg) {
+ ast_error(CHILD(ch, 0),
+ "only named arguments may follow *expression");
+ return NULL;
+ }
+ e = ast_for_expr(c, CHILD(ch, 0));
+ if (!e)
+ return NULL;
+ asdl_seq_SET(args, nargs++, e);
+ }
+ else if (TYPE(CHILD(ch, 1)) == comp_for) {
+ e = ast_for_genexp(c, ch);
+ if (!e)
+ return NULL;
+ asdl_seq_SET(args, nargs++, e);
+ }
+ else {
+ keyword_ty kw;
+ identifier key;
+ int k;
+ char *tmp;
+
+ /* CHILD(ch, 0) is test, but must be an identifier? */
+ e = ast_for_expr(c, CHILD(ch, 0));
+ if (!e)
+ return NULL;
+ /* f(lambda x: x[0] = 3) ends up getting parsed with
+ * LHS test = lambda x: x[0], and RHS test = 3.
+ * SF bug 132313 points out that complaining about a keyword
+ * then is very confusing.
+ */
+ if (e->kind == Lambda_kind) {
+ ast_error(CHILD(ch, 0),
+ "lambda cannot contain assignment");
+ return NULL;
+ } else if (e->kind != Name_kind) {
+ ast_error(CHILD(ch, 0), "keyword can't be an expression");
+ return NULL;
+ }
+ key = e->v.Name.id;
+ if (!forbidden_check(c, CHILD(ch, 0), PyBytes_AS_STRING(key)))
+ return NULL;
+ for (k = 0; k < nkeywords; k++) {
+ tmp = PyString_AS_STRING(
+ ((keyword_ty)asdl_seq_GET(keywords, k))->arg);
+ if (!strcmp(tmp, PyString_AS_STRING(key))) {
+ ast_error(CHILD(ch, 0), "keyword argument repeated");
+ return NULL;
+ }
+ }
+ e = ast_for_expr(c, CHILD(ch, 2));
+ if (!e)
+ return NULL;
+ kw = keyword(key, e, c->c_arena);
+ if (!kw)
+ return NULL;
+ asdl_seq_SET(keywords, nkeywords++, kw);
+ }
+ }
+ else if (TYPE(ch) == STAR) {
+ vararg = ast_for_expr(c, CHILD(n, i+1));
+ if (!vararg)
+ return NULL;
+ i++;
+ }
+ else if (TYPE(ch) == DOUBLESTAR) {
+ kwarg = ast_for_expr(c, CHILD(n, i+1));
+ if (!kwarg)
+ return NULL;
+ i++;
+ }
+ }
+
+ return Call(func, args, keywords, vararg, kwarg, func->lineno,
+ func->col_offset, c->c_arena);
+}
+
+static expr_ty
+ast_for_testlist(struct compiling *c, const node* n)
+{
+ /* testlist_comp: test (',' test)* [','] */
+ /* testlist: test (',' test)* [','] */
+ /* testlist_safe: test (',' test)+ [','] */
+ /* testlist1: test (',' test)* */
+ assert(NCH(n) > 0);
+ if (TYPE(n) == testlist_comp) {
+ if (NCH(n) > 1)
+ assert(TYPE(CHILD(n, 1)) != comp_for);
+ }
+ else {
+ assert(TYPE(n) == testlist ||
+ TYPE(n) == testlist_safe ||
+ TYPE(n) == testlist1);
+ }
+ if (NCH(n) == 1)
+ return ast_for_expr(c, CHILD(n, 0));
+ else {
+ asdl_seq *tmp = seq_for_testlist(c, n);
+ if (!tmp)
+ return NULL;
+ return Tuple(tmp, Load, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+}
+
+static expr_ty
+ast_for_testlist_comp(struct compiling *c, const node* n)
+{
+ /* testlist_comp: test ( comp_for | (',' test)* [','] ) */
+ /* argument: test [ comp_for ] */
+ assert(TYPE(n) == testlist_comp || TYPE(n) == argument);
+ if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == comp_for)
+ return ast_for_genexp(c, n);
+ return ast_for_testlist(c, n);
+}
+
+/* like ast_for_testlist() but returns a sequence */
+static asdl_seq*
+ast_for_class_bases(struct compiling *c, const node* n)
+{
+ /* testlist: test (',' test)* [','] */
+ assert(NCH(n) > 0);
+ REQ(n, testlist);
+ if (NCH(n) == 1) {
+ expr_ty base;
+ asdl_seq *bases = asdl_seq_new(1, c->c_arena);
+ if (!bases)
+ return NULL;
+ base = ast_for_expr(c, CHILD(n, 0));
+ if (!base)
+ return NULL;
+ asdl_seq_SET(bases, 0, base);
+ return bases;
+ }
+
+ return seq_for_testlist(c, n);
+}
+
+static stmt_ty
+ast_for_expr_stmt(struct compiling *c, const node *n)
+{
+ REQ(n, expr_stmt);
+ /* expr_stmt: testlist (augassign (yield_expr|testlist)
+ | ('=' (yield_expr|testlist))*)
+ testlist: test (',' test)* [',']
+ augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
+ | '<<=' | '>>=' | '**=' | '//='
+ test: ... here starts the operator precedence dance
+ */
+
+ if (NCH(n) == 1) {
+ expr_ty e = ast_for_testlist(c, CHILD(n, 0));
+ if (!e)
+ return NULL;
+
+ return Expr(e, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ else if (TYPE(CHILD(n, 1)) == augassign) {
+ expr_ty expr1, expr2;
+ operator_ty newoperator;
+ node *ch = CHILD(n, 0);
+
+ expr1 = ast_for_testlist(c, ch);
+ if (!expr1)
+ return NULL;
+ if(!set_context(c, expr1, Store, ch))
+ return NULL;
+ /* set_context checks that most expressions are not the left side.
+ Augmented assignments can only have a name, a subscript, or an
+ attribute on the left, though, so we have to explicitly check for
+ those. */
+ switch (expr1->kind) {
+ case Name_kind:
+ case Attribute_kind:
+ case Subscript_kind:
+ break;
+ default:
+ ast_error(ch, "illegal expression for augmented assignment");
+ return NULL;
+ }
+
+ ch = CHILD(n, 2);
+ if (TYPE(ch) == testlist)
+ expr2 = ast_for_testlist(c, ch);
+ else
+ expr2 = ast_for_expr(c, ch);
+ if (!expr2)
+ return NULL;
+
+ newoperator = ast_for_augassign(c, CHILD(n, 1));
+ if (!newoperator)
+ return NULL;
+
+ return AugAssign(expr1, newoperator, expr2, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else {
+ int i;
+ asdl_seq *targets;
+ node *value;
+ expr_ty expression;
+
+ /* a normal assignment */
+ REQ(CHILD(n, 1), EQUAL);
+ targets = asdl_seq_new(NCH(n) / 2, c->c_arena);
+ if (!targets)
+ return NULL;
+ for (i = 0; i < NCH(n) - 2; i += 2) {
+ expr_ty e;
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == yield_expr) {
+ ast_error(ch, "assignment to yield expression not possible");
+ return NULL;
+ }
+ e = ast_for_testlist(c, ch);
+ if (!e)
+ return NULL;
+
+ /* set context to assign */
+ if (!set_context(c, e, Store, CHILD(n, i)))
+ return NULL;
+
+ asdl_seq_SET(targets, i / 2, e);
+ }
+ value = CHILD(n, NCH(n) - 1);
+ if (TYPE(value) == testlist)
+ expression = ast_for_testlist(c, value);
+ else
+ expression = ast_for_expr(c, value);
+ if (!expression)
+ return NULL;
+ return Assign(targets, expression, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+}
+
+static stmt_ty
+ast_for_print_stmt(struct compiling *c, const node *n)
+{
+ /* print_stmt: 'print' ( [ test (',' test)* [','] ]
+ | '>>' test [ (',' test)+ [','] ] )
+ */
+ expr_ty dest = NULL, expression;
+ asdl_seq *seq = NULL;
+ bool nl;
+ int i, j, values_count, start = 1;
+
+ REQ(n, print_stmt);
+ if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) {
+ dest = ast_for_expr(c, CHILD(n, 2));
+ if (!dest)
+ return NULL;
+ start = 4;
+ }
+ values_count = (NCH(n) + 1 - start) / 2;
+ if (values_count) {
+ seq = asdl_seq_new(values_count, c->c_arena);
+ if (!seq)
+ return NULL;
+ for (i = start, j = 0; i < NCH(n); i += 2, ++j) {
+ expression = ast_for_expr(c, CHILD(n, i));
+ if (!expression)
+ return NULL;
+ asdl_seq_SET(seq, j, expression);
+ }
+ }
+ nl = (TYPE(CHILD(n, NCH(n) - 1)) == COMMA) ? false : true;
+ return Print(dest, seq, nl, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static asdl_seq *
+ast_for_exprlist(struct compiling *c, const node *n, expr_context_ty context)
+{
+ asdl_seq *seq;
+ int i;
+ expr_ty e;
+
+ REQ(n, exprlist);
+
+ seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
+ if (!seq)
+ return NULL;
+ for (i = 0; i < NCH(n); i += 2) {
+ e = ast_for_expr(c, CHILD(n, i));
+ if (!e)
+ return NULL;
+ asdl_seq_SET(seq, i / 2, e);
+ if (context && !set_context(c, e, context, CHILD(n, i)))
+ return NULL;
+ }
+ return seq;
+}
+
+static stmt_ty
+ast_for_del_stmt(struct compiling *c, const node *n)
+{
+ asdl_seq *expr_list;
+
+ /* del_stmt: 'del' exprlist */
+ REQ(n, del_stmt);
+
+ expr_list = ast_for_exprlist(c, CHILD(n, 1), Del);
+ if (!expr_list)
+ return NULL;
+ return Delete(expr_list, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static stmt_ty
+ast_for_flow_stmt(struct compiling *c, const node *n)
+{
+ /*
+ flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt
+ | yield_stmt
+ break_stmt: 'break'
+ continue_stmt: 'continue'
+ return_stmt: 'return' [testlist]
+ yield_stmt: yield_expr
+ yield_expr: 'yield' testlist
+ raise_stmt: 'raise' [test [',' test [',' test]]]
+ */
+ node *ch;
+
+ REQ(n, flow_stmt);
+ ch = CHILD(n, 0);
+ switch (TYPE(ch)) {
+ case break_stmt:
+ return Break(LINENO(n), n->n_col_offset, c->c_arena);
+ case continue_stmt:
+ return Continue(LINENO(n), n->n_col_offset, c->c_arena);
+ case yield_stmt: { /* will reduce to yield_expr */
+ expr_ty exp = ast_for_expr(c, CHILD(ch, 0));
+ if (!exp)
+ return NULL;
+ return Expr(exp, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ case return_stmt:
+ if (NCH(ch) == 1)
+ return Return(NULL, LINENO(n), n->n_col_offset, c->c_arena);
+ else {
+ expr_ty expression = ast_for_testlist(c, CHILD(ch, 1));
+ if (!expression)
+ return NULL;
+ return Return(expression, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ case raise_stmt:
+ if (NCH(ch) == 1)
+ return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ else if (NCH(ch) == 2) {
+ expr_ty expression = ast_for_expr(c, CHILD(ch, 1));
+ if (!expression)
+ return NULL;
+ return Raise(expression, NULL, NULL, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ }
+ else if (NCH(ch) == 4) {
+ expr_ty expr1, expr2;
+
+ expr1 = ast_for_expr(c, CHILD(ch, 1));
+ if (!expr1)
+ return NULL;
+ expr2 = ast_for_expr(c, CHILD(ch, 3));
+ if (!expr2)
+ return NULL;
+
+ return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else if (NCH(ch) == 6) {
+ expr_ty expr1, expr2, expr3;
+
+ expr1 = ast_for_expr(c, CHILD(ch, 1));
+ if (!expr1)
+ return NULL;
+ expr2 = ast_for_expr(c, CHILD(ch, 3));
+ if (!expr2)
+ return NULL;
+ expr3 = ast_for_expr(c, CHILD(ch, 5));
+ if (!expr3)
+ return NULL;
+
+ return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unexpected flow_stmt: %d", TYPE(ch));
+ return NULL;
+ }
+
+ PyErr_SetString(PyExc_SystemError, "unhandled flow statement");
+ return NULL;
+}
+
+static alias_ty
+alias_for_import_name(struct compiling *c, const node *n, int store)
+{
+ /*
+ import_as_name: NAME ['as' NAME]
+ dotted_as_name: dotted_name ['as' NAME]
+ dotted_name: NAME ('.' NAME)*
+ */
+ PyObject *str, *name;
+
+ loop:
+ switch (TYPE(n)) {
+ case import_as_name: {
+ node *name_node = CHILD(n, 0);
+ str = NULL;
+ if (NCH(n) == 3) {
+ node *str_node = CHILD(n, 2);
+ if (store && !forbidden_check(c, str_node, STR(str_node)))
+ return NULL;
+ str = NEW_IDENTIFIER(str_node);
+ if (!str)
+ return NULL;
+ }
+ else {
+ if (!forbidden_check(c, name_node, STR(name_node)))
+ return NULL;
+ }
+ name = NEW_IDENTIFIER(name_node);
+ if (!name)
+ return NULL;
+ return alias(name, str, c->c_arena);
+ }
+ case dotted_as_name:
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ else {
+ node *asname_node = CHILD(n, 2);
+ alias_ty a = alias_for_import_name(c, CHILD(n, 0), 0);
+ if (!a)
+ return NULL;
+ assert(!a->asname);
+ if (!forbidden_check(c, asname_node, STR(asname_node)))
+ return NULL;
+ a->asname = NEW_IDENTIFIER(asname_node);
+ if (!a->asname)
+ return NULL;
+ return a;
+ }
+ break;
+ case dotted_name:
+ if (NCH(n) == 1) {
+ node *name_node = CHILD(n, 0);
+ if (store && !forbidden_check(c, name_node, STR(name_node)))
+ return NULL;
+ name = NEW_IDENTIFIER(name_node);
+ if (!name)
+ return NULL;
+ return alias(name, NULL, c->c_arena);
+ }
+ else {
+ /* Create a string of the form "a.b.c" */
+ int i;
+ size_t len;
+ char *s;
+
+ len = 0;
+ for (i = 0; i < NCH(n); i += 2)
+ /* length of string plus one for the dot */
+ len += strlen(STR(CHILD(n, i))) + 1;
+ len--; /* the last name doesn't have a dot */
+ str = PyString_FromStringAndSize(NULL, len);
+ if (!str)
+ return NULL;
+ s = PyString_AS_STRING(str);
+ if (!s)
+ return NULL;
+ for (i = 0; i < NCH(n); i += 2) {
+ char *sch = STR(CHILD(n, i));
+ strcpy(s, STR(CHILD(n, i)));
+ s += strlen(sch);
+ *s++ = '.';
+ }
+ --s;
+ *s = '\0';
+ PyString_InternInPlace(&str);
+ PyArena_AddPyObject(c->c_arena, str);
+ return alias(str, NULL, c->c_arena);
+ }
+ break;
+ case STAR:
+ str = PyString_InternFromString("*");
+ if (!str)
+ return NULL;
+ PyArena_AddPyObject(c->c_arena, str);
+ return alias(str, NULL, c->c_arena);
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unexpected import name: %d", TYPE(n));
+ return NULL;
+ }
+
+ PyErr_SetString(PyExc_SystemError, "unhandled import name condition");
+ return NULL;
+}
+
+static stmt_ty
+ast_for_import_stmt(struct compiling *c, const node *n)
+{
+ /*
+ import_stmt: import_name | import_from
+ import_name: 'import' dotted_as_names
+ import_from: 'from' ('.'* dotted_name | '.') 'import'
+ ('*' | '(' import_as_names ')' | import_as_names)
+ */
+ int lineno;
+ int col_offset;
+ int i;
+ asdl_seq *aliases;
+
+ REQ(n, import_stmt);
+ lineno = LINENO(n);
+ col_offset = n->n_col_offset;
+ n = CHILD(n, 0);
+ if (TYPE(n) == import_name) {
+ n = CHILD(n, 1);
+ REQ(n, dotted_as_names);
+ aliases = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
+ if (!aliases)
+ return NULL;
+ for (i = 0; i < NCH(n); i += 2) {
+ alias_ty import_alias = alias_for_import_name(c, CHILD(n, i), 1);
+ if (!import_alias)
+ return NULL;
+ asdl_seq_SET(aliases, i / 2, import_alias);
+ }
+ return Import(aliases, lineno, col_offset, c->c_arena);
+ }
+ else if (TYPE(n) == import_from) {
+ int n_children;
+ int idx, ndots = 0;
+ alias_ty mod = NULL;
+ identifier modname = NULL;
+
+ /* Count the number of dots (for relative imports) and check for the
+ optional module name */
+ for (idx = 1; idx < NCH(n); idx++) {
+ if (TYPE(CHILD(n, idx)) == dotted_name) {
+ mod = alias_for_import_name(c, CHILD(n, idx), 0);
+ if (!mod)
+ return NULL;
+ idx++;
+ break;
+ } else if (TYPE(CHILD(n, idx)) != DOT) {
+ break;
+ }
+ ndots++;
+ }
+ idx++; /* skip over the 'import' keyword */
+ switch (TYPE(CHILD(n, idx))) {
+ case STAR:
+ /* from ... import * */
+ n = CHILD(n, idx);
+ n_children = 1;
+ break;
+ case LPAR:
+ /* from ... import (x, y, z) */
+ n = CHILD(n, idx + 1);
+ n_children = NCH(n);
+ break;
+ case import_as_names:
+ /* from ... import x, y, z */
+ n = CHILD(n, idx);
+ n_children = NCH(n);
+ if (n_children % 2 == 0) {
+ ast_error(n, "trailing comma not allowed without"
+ " surrounding parentheses");
+ return NULL;
+ }
+ break;
+ default:
+ ast_error(n, "Unexpected node-type in from-import");
+ return NULL;
+ }
+
+ aliases = asdl_seq_new((n_children + 1) / 2, c->c_arena);
+ if (!aliases)
+ return NULL;
+
+ /* handle "from ... import *" special b/c there's no children */
+ if (TYPE(n) == STAR) {
+ alias_ty import_alias = alias_for_import_name(c, n, 1);
+ if (!import_alias)
+ return NULL;
+ asdl_seq_SET(aliases, 0, import_alias);
+ }
+ else {
+ for (i = 0; i < NCH(n); i += 2) {
+ alias_ty import_alias = alias_for_import_name(c, CHILD(n, i), 1);
+ if (!import_alias)
+ return NULL;
+ asdl_seq_SET(aliases, i / 2, import_alias);
+ }
+ }
+ if (mod != NULL)
+ modname = mod->name;
+ return ImportFrom(modname, aliases, ndots, lineno, col_offset,
+ c->c_arena);
+ }
+ PyErr_Format(PyExc_SystemError,
+ "unknown import statement: starts with command '%s'",
+ STR(CHILD(n, 0)));
+ return NULL;
+}
+
+static stmt_ty
+ast_for_global_stmt(struct compiling *c, const node *n)
+{
+ /* global_stmt: 'global' NAME (',' NAME)* */
+ identifier name;
+ asdl_seq *s;
+ int i;
+
+ REQ(n, global_stmt);
+ s = asdl_seq_new(NCH(n) / 2, c->c_arena);
+ if (!s)
+ return NULL;
+ for (i = 1; i < NCH(n); i += 2) {
+ name = NEW_IDENTIFIER(CHILD(n, i));
+ if (!name)
+ return NULL;
+ asdl_seq_SET(s, i / 2, name);
+ }
+ return Global(s, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static stmt_ty
+ast_for_exec_stmt(struct compiling *c, const node *n)
+{
+ expr_ty expr1, globals = NULL, locals = NULL;
+ int n_children = NCH(n);
+ if (n_children != 2 && n_children != 4 && n_children != 6) {
+ PyErr_Format(PyExc_SystemError,
+ "poorly formed 'exec' statement: %d parts to statement",
+ n_children);
+ return NULL;
+ }
+
+ /* exec_stmt: 'exec' expr ['in' test [',' test]] */
+ REQ(n, exec_stmt);
+ expr1 = ast_for_expr(c, CHILD(n, 1));
+ if (!expr1)
+ return NULL;
+
+ if (expr1->kind == Tuple_kind && n_children < 4 &&
+ (asdl_seq_LEN(expr1->v.Tuple.elts) == 2 ||
+ asdl_seq_LEN(expr1->v.Tuple.elts) == 3)) {
+ /* Backwards compatibility: passing exec args as a tuple */
+ globals = asdl_seq_GET(expr1->v.Tuple.elts, 1);
+ if (asdl_seq_LEN(expr1->v.Tuple.elts) == 3) {
+ locals = asdl_seq_GET(expr1->v.Tuple.elts, 2);
+ }
+ expr1 = asdl_seq_GET(expr1->v.Tuple.elts, 0);
+ }
+
+ if (n_children >= 4) {
+ globals = ast_for_expr(c, CHILD(n, 3));
+ if (!globals)
+ return NULL;
+ }
+ if (n_children == 6) {
+ locals = ast_for_expr(c, CHILD(n, 5));
+ if (!locals)
+ return NULL;
+ }
+
+ return Exec(expr1, globals, locals, LINENO(n), n->n_col_offset,
+ c->c_arena);
+}
+
+static stmt_ty
+ast_for_assert_stmt(struct compiling *c, const node *n)
+{
+ /* assert_stmt: 'assert' test [',' test] */
+ REQ(n, assert_stmt);
+ if (NCH(n) == 2) {
+ expr_ty expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ return Assert(expression, NULL, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else if (NCH(n) == 4) {
+ expr_ty expr1, expr2;
+
+ expr1 = ast_for_expr(c, CHILD(n, 1));
+ if (!expr1)
+ return NULL;
+ expr2 = ast_for_expr(c, CHILD(n, 3));
+ if (!expr2)
+ return NULL;
+
+ return Assert(expr1, expr2, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ PyErr_Format(PyExc_SystemError,
+ "improper number of parts to 'assert' statement: %d",
+ NCH(n));
+ return NULL;
+}
+
+static asdl_seq *
+ast_for_suite(struct compiling *c, const node *n)
+{
+ /* suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT */
+ asdl_seq *seq;
+ stmt_ty s;
+ int i, total, num, end, pos = 0;
+ node *ch;
+
+ REQ(n, suite);
+
+ total = num_stmts(n);
+ seq = asdl_seq_new(total, c->c_arena);
+ if (!seq)
+ return NULL;
+ if (TYPE(CHILD(n, 0)) == simple_stmt) {
+ n = CHILD(n, 0);
+ /* simple_stmt always ends with a NEWLINE,
+ and may have a trailing SEMI
+ */
+ end = NCH(n) - 1;
+ if (TYPE(CHILD(n, end - 1)) == SEMI)
+ end--;
+ /* loop by 2 to skip semi-colons */
+ for (i = 0; i < end; i += 2) {
+ ch = CHILD(n, i);
+ s = ast_for_stmt(c, ch);
+ if (!s)
+ return NULL;
+ asdl_seq_SET(seq, pos++, s);
+ }
+ }
+ else {
+ for (i = 2; i < (NCH(n) - 1); i++) {
+ ch = CHILD(n, i);
+ REQ(ch, stmt);
+ num = num_stmts(ch);
+ if (num == 1) {
+ /* small_stmt or compound_stmt with only one child */
+ s = ast_for_stmt(c, ch);
+ if (!s)
+ return NULL;
+ asdl_seq_SET(seq, pos++, s);
+ }
+ else {
+ int j;
+ ch = CHILD(ch, 0);
+ REQ(ch, simple_stmt);
+ for (j = 0; j < NCH(ch); j += 2) {
+ /* statement terminates with a semi-colon ';' */
+ if (NCH(CHILD(ch, j)) == 0) {
+ assert((j + 1) == NCH(ch));
+ break;
+ }
+ s = ast_for_stmt(c, CHILD(ch, j));
+ if (!s)
+ return NULL;
+ asdl_seq_SET(seq, pos++, s);
+ }
+ }
+ }
+ }
+ assert(pos == seq->size);
+ return seq;
+}
+
+static stmt_ty
+ast_for_if_stmt(struct compiling *c, const node *n)
+{
+ /* if_stmt: 'if' test ':' suite ('elif' test ':' suite)*
+ ['else' ':' suite]
+ */
+ char *s;
+
+ REQ(n, if_stmt);
+
+ if (NCH(n) == 4) {
+ expr_ty expression;
+ asdl_seq *suite_seq;
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, 3));
+ if (!suite_seq)
+ return NULL;
+
+ return If(expression, suite_seq, NULL, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+
+ s = STR(CHILD(n, 4));
+ /* s[2], the third character in the string, will be
+ 's' for el_s_e, or
+ 'i' for el_i_f
+ */
+ if (s[2] == 's') {
+ expr_ty expression;
+ asdl_seq *seq1, *seq2;
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ seq1 = ast_for_suite(c, CHILD(n, 3));
+ if (!seq1)
+ return NULL;
+ seq2 = ast_for_suite(c, CHILD(n, 6));
+ if (!seq2)
+ return NULL;
+
+ return If(expression, seq1, seq2, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else if (s[2] == 'i') {
+ int i, n_elif, has_else = 0;
+ expr_ty expression;
+ asdl_seq *suite_seq;
+ asdl_seq *orelse = NULL;
+ n_elif = NCH(n) - 4;
+ /* must reference the child n_elif+1 since 'else' token is third,
+ not fourth, child from the end. */
+ if (TYPE(CHILD(n, (n_elif + 1))) == NAME
+ && STR(CHILD(n, (n_elif + 1)))[2] == 's') {
+ has_else = 1;
+ n_elif -= 3;
+ }
+ n_elif /= 4;
+
+ if (has_else) {
+ asdl_seq *suite_seq2;
+
+ orelse = asdl_seq_new(1, c->c_arena);
+ if (!orelse)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, NCH(n) - 6));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4));
+ if (!suite_seq)
+ return NULL;
+ suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1));
+ if (!suite_seq2)
+ return NULL;
+
+ asdl_seq_SET(orelse, 0,
+ If(expression, suite_seq, suite_seq2,
+ LINENO(CHILD(n, NCH(n) - 6)),
+ CHILD(n, NCH(n) - 6)->n_col_offset,
+ c->c_arena));
+ /* the just-created orelse handled the last elif */
+ n_elif--;
+ }
+
+ for (i = 0; i < n_elif; i++) {
+ int off = 5 + (n_elif - i - 1) * 4;
+ asdl_seq *newobj = asdl_seq_new(1, c->c_arena);
+ if (!newobj)
+ return NULL;
+ expression = ast_for_expr(c, CHILD(n, off));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, off + 2));
+ if (!suite_seq)
+ return NULL;
+
+ asdl_seq_SET(newobj, 0,
+ If(expression, suite_seq, orelse,
+ LINENO(CHILD(n, off)),
+ CHILD(n, off)->n_col_offset, c->c_arena));
+ orelse = newobj;
+ }
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, 3));
+ if (!suite_seq)
+ return NULL;
+ return If(expression, suite_seq, orelse,
+ LINENO(n), n->n_col_offset, c->c_arena);
+ }
+
+ PyErr_Format(PyExc_SystemError,
+ "unexpected token in 'if' statement: %s", s);
+ return NULL;
+}
+
+static stmt_ty
+ast_for_while_stmt(struct compiling *c, const node *n)
+{
+ /* while_stmt: 'while' test ':' suite ['else' ':' suite] */
+ REQ(n, while_stmt);
+
+ if (NCH(n) == 4) {
+ expr_ty expression;
+ asdl_seq *suite_seq;
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, 3));
+ if (!suite_seq)
+ return NULL;
+ return While(expression, suite_seq, NULL, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+ else if (NCH(n) == 7) {
+ expr_ty expression;
+ asdl_seq *seq1, *seq2;
+
+ expression = ast_for_expr(c, CHILD(n, 1));
+ if (!expression)
+ return NULL;
+ seq1 = ast_for_suite(c, CHILD(n, 3));
+ if (!seq1)
+ return NULL;
+ seq2 = ast_for_suite(c, CHILD(n, 6));
+ if (!seq2)
+ return NULL;
+
+ return While(expression, seq1, seq2, LINENO(n), n->n_col_offset,
+ c->c_arena);
+ }
+
+ PyErr_Format(PyExc_SystemError,
+ "wrong number of tokens for 'while' statement: %d",
+ NCH(n));
+ return NULL;
+}
+
+static stmt_ty
+ast_for_for_stmt(struct compiling *c, const node *n)
+{
+ asdl_seq *_target, *seq = NULL, *suite_seq;
+ expr_ty expression;
+ expr_ty target, first;
+ const node *node_target;
+ /* for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] */
+ REQ(n, for_stmt);
+
+ if (NCH(n) == 9) {
+ seq = ast_for_suite(c, CHILD(n, 8));
+ if (!seq)
+ return NULL;
+ }
+
+ node_target = CHILD(n, 1);
+ _target = ast_for_exprlist(c, node_target, Store);
+ if (!_target)
+ return NULL;
+ /* Check the # of children rather than the length of _target, since
+ for x, in ... has 1 element in _target, but still requires a Tuple. */
+ first = (expr_ty)asdl_seq_GET(_target, 0);
+ if (NCH(node_target) == 1)
+ target = first;
+ else
+ target = Tuple(_target, Store, first->lineno, first->col_offset, c->c_arena);
+
+ expression = ast_for_testlist(c, CHILD(n, 3));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, CHILD(n, 5));
+ if (!suite_seq)
+ return NULL;
+
+ return For(target, expression, suite_seq, seq, LINENO(n), n->n_col_offset,
+ c->c_arena);
+}
+
+static excepthandler_ty
+ast_for_except_clause(struct compiling *c, const node *exc, node *body)
+{
+ /* except_clause: 'except' [test [(',' | 'as') test]] */
+ REQ(exc, except_clause);
+ REQ(body, suite);
+
+ if (NCH(exc) == 1) {
+ asdl_seq *suite_seq = ast_for_suite(c, body);
+ if (!suite_seq)
+ return NULL;
+
+ return ExceptHandler(NULL, NULL, suite_seq, LINENO(exc),
+ exc->n_col_offset, c->c_arena);
+ }
+ else if (NCH(exc) == 2) {
+ expr_ty expression;
+ asdl_seq *suite_seq;
+
+ expression = ast_for_expr(c, CHILD(exc, 1));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, body);
+ if (!suite_seq)
+ return NULL;
+
+ return ExceptHandler(expression, NULL, suite_seq, LINENO(exc),
+ exc->n_col_offset, c->c_arena);
+ }
+ else if (NCH(exc) == 4) {
+ asdl_seq *suite_seq;
+ expr_ty expression;
+ expr_ty e = ast_for_expr(c, CHILD(exc, 3));
+ if (!e)
+ return NULL;
+ if (!set_context(c, e, Store, CHILD(exc, 3)))
+ return NULL;
+ expression = ast_for_expr(c, CHILD(exc, 1));
+ if (!expression)
+ return NULL;
+ suite_seq = ast_for_suite(c, body);
+ if (!suite_seq)
+ return NULL;
+
+ return ExceptHandler(expression, e, suite_seq, LINENO(exc),
+ exc->n_col_offset, c->c_arena);
+ }
+
+ PyErr_Format(PyExc_SystemError,
+ "wrong number of children for 'except' clause: %d",
+ NCH(exc));
+ return NULL;
+}
+
+static stmt_ty
+ast_for_try_stmt(struct compiling *c, const node *n)
+{
+ const int nch = NCH(n);
+ int n_except = (nch - 3)/3;
+ asdl_seq *body, *orelse = NULL, *finally = NULL;
+
+ REQ(n, try_stmt);
+
+ body = ast_for_suite(c, CHILD(n, 2));
+ if (body == NULL)
+ return NULL;
+
+ if (TYPE(CHILD(n, nch - 3)) == NAME) {
+ if (strcmp(STR(CHILD(n, nch - 3)), "finally") == 0) {
+ if (nch >= 9 && TYPE(CHILD(n, nch - 6)) == NAME) {
+ /* we can assume it's an "else",
+ because nch >= 9 for try-else-finally and
+ it would otherwise have a type of except_clause */
+ orelse = ast_for_suite(c, CHILD(n, nch - 4));
+ if (orelse == NULL)
+ return NULL;
+ n_except--;
+ }
+
+ finally = ast_for_suite(c, CHILD(n, nch - 1));
+ if (finally == NULL)
+ return NULL;
+ n_except--;
+ }
+ else {
+ /* we can assume it's an "else",
+ otherwise it would have a type of except_clause */
+ orelse = ast_for_suite(c, CHILD(n, nch - 1));
+ if (orelse == NULL)
+ return NULL;
+ n_except--;
+ }
+ }
+ else if (TYPE(CHILD(n, nch - 3)) != except_clause) {
+ ast_error(n, "malformed 'try' statement");
+ return NULL;
+ }
+
+ if (n_except > 0) {
+ int i;
+ stmt_ty except_st;
+ /* process except statements to create a try ... except */
+ asdl_seq *handlers = asdl_seq_new(n_except, c->c_arena);
+ if (handlers == NULL)
+ return NULL;
+
+ for (i = 0; i < n_except; i++) {
+ excepthandler_ty e = ast_for_except_clause(c, CHILD(n, 3 + i * 3),
+ CHILD(n, 5 + i * 3));
+ if (!e)
+ return NULL;
+ asdl_seq_SET(handlers, i, e);
+ }
+
+ except_st = TryExcept(body, handlers, orelse, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ if (!finally)
+ return except_st;
+
+ /* if a 'finally' is present too, we nest the TryExcept within a
+ TryFinally to emulate try ... except ... finally */
+ body = asdl_seq_new(1, c->c_arena);
+ if (body == NULL)
+ return NULL;
+ asdl_seq_SET(body, 0, except_st);
+ }
+
+ /* must be a try ... finally (except clauses are in body, if any exist) */
+ assert(finally != NULL);
+ return TryFinally(body, finally, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+/* with_item: test ['as' expr] */
+static stmt_ty
+ast_for_with_item(struct compiling *c, const node *n, asdl_seq *content)
+{
+ expr_ty context_expr, optional_vars = NULL;
+
+ REQ(n, with_item);
+ context_expr = ast_for_expr(c, CHILD(n, 0));
+ if (!context_expr)
+ return NULL;
+ if (NCH(n) == 3) {
+ optional_vars = ast_for_expr(c, CHILD(n, 2));
+
+ if (!optional_vars) {
+ return NULL;
+ }
+ if (!set_context(c, optional_vars, Store, n)) {
+ return NULL;
+ }
+ }
+
+ return With(context_expr, optional_vars, content, LINENO(n),
+ n->n_col_offset, c->c_arena);
+}
+
+/* with_stmt: 'with' with_item (',' with_item)* ':' suite */
+static stmt_ty
+ast_for_with_stmt(struct compiling *c, const node *n)
+{
+ int i;
+ stmt_ty ret;
+ asdl_seq *inner;
+
+ REQ(n, with_stmt);
+
+ /* process the with items inside-out */
+ i = NCH(n) - 1;
+ /* the suite of the innermost with item is the suite of the with stmt */
+ inner = ast_for_suite(c, CHILD(n, i));
+ if (!inner)
+ return NULL;
+
+ for (;;) {
+ i -= 2;
+ ret = ast_for_with_item(c, CHILD(n, i), inner);
+ if (!ret)
+ return NULL;
+ /* was this the last item? */
+ if (i == 1)
+ break;
+ /* if not, wrap the result so far in a new sequence */
+ inner = asdl_seq_new(1, c->c_arena);
+ if (!inner)
+ return NULL;
+ asdl_seq_SET(inner, 0, ret);
+ }
+
+ return ret;
+}
+
+static stmt_ty
+ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
+{
+ /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
+ PyObject *classname;
+ asdl_seq *bases, *s;
+
+ REQ(n, classdef);
+
+ if (!forbidden_check(c, n, STR(CHILD(n, 1))))
+ return NULL;
+
+ if (NCH(n) == 4) {
+ s = ast_for_suite(c, CHILD(n, 3));
+ if (!s)
+ return NULL;
+ classname = NEW_IDENTIFIER(CHILD(n, 1));
+ if (!classname)
+ return NULL;
+ return ClassDef(classname, NULL, s, decorator_seq, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ }
+ /* check for empty base list */
+ if (TYPE(CHILD(n,3)) == RPAR) {
+ s = ast_for_suite(c, CHILD(n,5));
+ if (!s)
+ return NULL;
+ classname = NEW_IDENTIFIER(CHILD(n, 1));
+ if (!classname)
+ return NULL;
+ return ClassDef(classname, NULL, s, decorator_seq, LINENO(n),
+ n->n_col_offset, c->c_arena);
+ }
+
+ /* else handle the base class list */
+ bases = ast_for_class_bases(c, CHILD(n, 3));
+ if (!bases)
+ return NULL;
+
+ s = ast_for_suite(c, CHILD(n, 6));
+ if (!s)
+ return NULL;
+ classname = NEW_IDENTIFIER(CHILD(n, 1));
+ if (!classname)
+ return NULL;
+ return ClassDef(classname, bases, s, decorator_seq,
+ LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static stmt_ty
+ast_for_stmt(struct compiling *c, const node *n)
+{
+ if (TYPE(n) == stmt) {
+ assert(NCH(n) == 1);
+ n = CHILD(n, 0);
+ }
+ if (TYPE(n) == simple_stmt) {
+ assert(num_stmts(n) == 1);
+ n = CHILD(n, 0);
+ }
+ if (TYPE(n) == small_stmt) {
+ n = CHILD(n, 0);
+ /* small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt
+ | flow_stmt | import_stmt | global_stmt | exec_stmt
+ | assert_stmt
+ */
+ switch (TYPE(n)) {
+ case expr_stmt:
+ return ast_for_expr_stmt(c, n);
+ case print_stmt:
+ return ast_for_print_stmt(c, n);
+ case del_stmt:
+ return ast_for_del_stmt(c, n);
+ case pass_stmt:
+ return Pass(LINENO(n), n->n_col_offset, c->c_arena);
+ case flow_stmt:
+ return ast_for_flow_stmt(c, n);
+ case import_stmt:
+ return ast_for_import_stmt(c, n);
+ case global_stmt:
+ return ast_for_global_stmt(c, n);
+ case exec_stmt:
+ return ast_for_exec_stmt(c, n);
+ case assert_stmt:
+ return ast_for_assert_stmt(c, n);
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unhandled small_stmt: TYPE=%d NCH=%d\n",
+ TYPE(n), NCH(n));
+ return NULL;
+ }
+ }
+ else {
+ /* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt
+ | funcdef | classdef | decorated
+ */
+ node *ch = CHILD(n, 0);
+ REQ(n, compound_stmt);
+ switch (TYPE(ch)) {
+ case if_stmt:
+ return ast_for_if_stmt(c, ch);
+ case while_stmt:
+ return ast_for_while_stmt(c, ch);
+ case for_stmt:
+ return ast_for_for_stmt(c, ch);
+ case try_stmt:
+ return ast_for_try_stmt(c, ch);
+ case with_stmt:
+ return ast_for_with_stmt(c, ch);
+ case funcdef:
+ return ast_for_funcdef(c, ch, NULL);
+ case classdef:
+ return ast_for_classdef(c, ch, NULL);
+ case decorated:
+ return ast_for_decorated(c, ch);
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unhandled small_stmt: TYPE=%d NCH=%d\n",
+ TYPE(n), NCH(n));
+ return NULL;
+ }
+ }
+}
+
+static PyObject *
+parsenumber(struct compiling *c, const char *s)
+{
+ const char *end;
+ long x;
+ double dx;
+#ifndef WITHOUT_COMPLEX
+ Py_complex complex;
+ int imflag;
+#endif
+
+ assert(s != NULL);
+ errno = 0;
+ end = s + strlen(s) - 1;
+#ifndef WITHOUT_COMPLEX
+ imflag = *end == 'j' || *end == 'J';
+#endif
+ if (*end == 'l' || *end == 'L')
+ return PyLong_FromString((char *)s, (char **)0, 0);
+ x = PyOS_strtol((char *)s, (char **)&end, 0);
+ if (*end == '\0') {
+ if (errno != 0)
+ return PyLong_FromString((char *)s, (char **)0, 0);
+ return PyInt_FromLong(x);
+ }
+ /* XXX Huge floats may silently fail */
+#ifndef WITHOUT_COMPLEX
+ if (imflag) {
+ complex.real = 0.;
+ complex.imag = PyOS_string_to_double(s, (char **)&end, NULL);
+ if (complex.imag == -1.0 && PyErr_Occurred())
+ return NULL;
+ return PyComplex_FromCComplex(complex);
+ }
+ else
+#endif
+ {
+ dx = PyOS_string_to_double(s, NULL, NULL);
+ if (dx == -1.0 && PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble(dx);
+ }
+}
+
+static PyObject *
+decode_utf8(struct compiling *c, const char **sPtr, const char *end, char* encoding)
+{
+#ifndef Py_USING_UNICODE
+ Py_FatalError("decode_utf8 should not be called in this build.");
+ return NULL;
+#else
+ PyObject *u, *v;
+ char *s, *t;
+ t = s = (char *)*sPtr;
+ /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */
+ while (s < end && (*s & 0x80)) s++;
+ *sPtr = s;
+ u = PyUnicode_DecodeUTF8(t, s - t, NULL);
+ if (u == NULL)
+ return NULL;
+ v = PyUnicode_AsEncodedString(u, encoding, NULL);
+ Py_DECREF(u);
+ return v;
+#endif
+}
+
+#ifdef Py_USING_UNICODE
+static PyObject *
+decode_unicode(struct compiling *c, const char *s, size_t len, int rawmode, const char *encoding)
+{
+ PyObject *v;
+ PyObject *u = NULL;
+ char *buf;
+ char *p;
+ const char *end;
+ if (encoding != NULL && strcmp(encoding, "iso-8859-1")) {
+ /* check for integer overflow */
+ if (len > PY_SIZE_MAX / 6)
+ return NULL;
+ /* "<C3><A4>" (2 bytes) may become "\U000000E4" (10 bytes), or 1:5
+ "\ä" (3 bytes) may become "\u005c\U000000E4" (16 bytes), or ~1:6 */
+ u = PyString_FromStringAndSize((char *)NULL, len * 6);
+ if (u == NULL)
+ return NULL;
+ p = buf = PyString_AsString(u);
+ end = s + len;
+ while (s < end) {
+ if (*s == '\\') {
+ *p++ = *s++;
+ if (*s & 0x80) {
+ strcpy(p, "u005c");
+ p += 5;
+ }
+ }
+ if (*s & 0x80) { /* XXX inefficient */
+ PyObject *w;
+ char *r;
+ Py_ssize_t rn, i;
+ w = decode_utf8(c, &s, end, "utf-32-be");
+ if (w == NULL) {
+ Py_DECREF(u);
+ return NULL;
+ }
+ r = PyString_AsString(w);
+ rn = PyString_Size(w);
+ assert(rn % 4 == 0);
+ for (i = 0; i < rn; i += 4) {
+ sprintf(p, "\\U%02x%02x%02x%02x",
+ r[i + 0] & 0xFF,
+ r[i + 1] & 0xFF,
+ r[i + 2] & 0xFF,
+ r[i + 3] & 0xFF);
+ p += 10;
+ }
+ Py_DECREF(w);
+ } else {
+ *p++ = *s++;
+ }
+ }
+ len = p - buf;
+ s = buf;
+ }
+ if (rawmode)
+ v = PyUnicode_DecodeRawUnicodeEscape(s, len, NULL);
+ else
+ v = PyUnicode_DecodeUnicodeEscape(s, len, NULL);
+ Py_XDECREF(u);
+ return v;
+}
+#endif
+
+/* s is a Python string literal, including the bracketing quote characters,
+ * and r &/or u prefixes (if any), and embedded escape sequences (if any).
+ * parsestr parses it, and returns the decoded Python string object.
+ */
+static PyObject *
+parsestr(struct compiling *c, const node *n, const char *s)
+{
+ size_t len, i;
+ int quote = Py_CHARMASK(*s);
+ int rawmode = 0;
+ int need_encoding;
+ int unicode = c->c_future_unicode;
+ int bytes = 0;
+
+ if (isalpha(quote) || quote == '_') {
+ if (quote == 'u' || quote == 'U') {
+ quote = *++s;
+ unicode = 1;
+ }
+ if (quote == 'b' || quote == 'B') {
+ quote = *++s;
+ unicode = 0;
+ bytes = 1;
+ }
+ if (quote == 'r' || quote == 'R') {
+ quote = *++s;
+ rawmode = 1;
+ }
+ }
+ if (quote != '\'' && quote != '\"') {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ s++;
+ len = strlen(s);
+ if (len > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "string to parse is too long");
+ return NULL;
+ }
+ if (s[--len] != quote) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ if (len >= 4 && s[0] == quote && s[1] == quote) {
+ s += 2;
+ len -= 2;
+ if (s[--len] != quote || s[--len] != quote) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ }
+ if (Py_Py3kWarningFlag && bytes) {
+ for (i = 0; i < len; i++) {
+ if ((unsigned char)s[i] > 127) {
+ if (!ast_warn(c, n,
+ "non-ascii bytes literals not supported in 3.x"))
+ return NULL;
+ break;
+ }
+ }
+ }
+#ifdef Py_USING_UNICODE
+ if (unicode || Py_UnicodeFlag) {
+ return decode_unicode(c, s, len, rawmode, c->c_encoding);
+ }
+#endif
+ need_encoding = (c->c_encoding != NULL &&
+ strcmp(c->c_encoding, "utf-8") != 0 &&
+ strcmp(c->c_encoding, "iso-8859-1") != 0);
+ if (rawmode || strchr(s, '\\') == NULL) {
+ if (need_encoding) {
+#ifndef Py_USING_UNICODE
+ /* This should not happen - we never see any other
+ encoding. */
+ Py_FatalError(
+ "cannot deal with encodings in this build.");
+#else
+ PyObject *v, *u = PyUnicode_DecodeUTF8(s, len, NULL);
+ if (u == NULL)
+ return NULL;
+ v = PyUnicode_AsEncodedString(u, c->c_encoding, NULL);
+ Py_DECREF(u);
+ return v;
+#endif
+ } else {
+ return PyString_FromStringAndSize(s, len);
+ }
+ }
+
+ return PyString_DecodeEscape(s, len, NULL, unicode,
+ need_encoding ? c->c_encoding : NULL);
+}
+
+/* Build a Python string object out of a STRING atom. This takes care of
+ * compile-time literal catenation, calling parsestr() on each piece, and
+ * pasting the intermediate results together.
+ */
+static PyObject *
+parsestrplus(struct compiling *c, const node *n)
+{
+ PyObject *v;
+ int i;
+ REQ(CHILD(n, 0), STRING);
+ if ((v = parsestr(c, n, STR(CHILD(n, 0)))) != NULL) {
+ /* String literal concatenation */
+ for (i = 1; i < NCH(n); i++) {
+ PyObject *s;
+ s = parsestr(c, n, STR(CHILD(n, i)));
+ if (s == NULL)
+ goto onError;
+ if (PyString_Check(v) && PyString_Check(s)) {
+ PyString_ConcatAndDel(&v, s);
+ if (v == NULL)
+ goto onError;
+ }
+#ifdef Py_USING_UNICODE
+ else {
+ PyObject *temp = PyUnicode_Concat(v, s);
+ Py_DECREF(s);
+ Py_DECREF(v);
+ v = temp;
+ if (v == NULL)
+ goto onError;
+ }
+#endif
+ }
+ }
+ return v;
+
+ onError:
+ Py_XDECREF(v);
+ return NULL;
+}
diff --git a/contrib/tools/python/src/Python/bltinmodule.c b/contrib/tools/python/src/Python/bltinmodule.c
new file mode 100644
index 0000000000..4b819da8b3
--- /dev/null
+++ b/contrib/tools/python/src/Python/bltinmodule.c
@@ -0,0 +1,3081 @@
+/* Built-in functions */
+
+#include "Python.h"
+#include "Python-ast.h"
+
+#include "node.h"
+#include "code.h"
+#include "eval.h"
+
+#include <ctype.h>
+#include <float.h> /* for DBL_MANT_DIG and friends */
+
+#ifdef RISCOS
+#include "unixstuff.h"
+#endif
+
+/* The default encoding used by the platform file system APIs
+ Can remain NULL for all platforms that don't have such a concept
+*/
+#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T)
+const char *Py_FileSystemDefaultEncoding = "mbcs";
+#elif defined(__APPLE__)
+const char *Py_FileSystemDefaultEncoding = "utf-8";
+#else
+const char *Py_FileSystemDefaultEncoding = NULL; /* use default */
+#endif
+
+/* Forward */
+static PyObject *filterstring(PyObject *, PyObject *);
+#ifdef Py_USING_UNICODE
+static PyObject *filterunicode(PyObject *, PyObject *);
+#endif
+static PyObject *filtertuple (PyObject *, PyObject *);
+
+static PyObject *
+builtin___import__(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"name", "globals", "locals", "fromlist",
+ "level", 0};
+ char *name;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
+ PyObject *fromlist = NULL;
+ int level = -1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|OOOi:__import__",
+ kwlist, &name, &globals, &locals, &fromlist, &level))
+ return NULL;
+ return PyImport_ImportModuleLevel(name, globals, locals,
+ fromlist, level);
+}
+
+PyDoc_STRVAR(import_doc,
+"__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\
+\n\
+Import a module. Because this function is meant for use by the Python\n\
+interpreter and not for general use, it is better to use\n\
+importlib.import_module() to programmatically import a module.\n\
+\n\
+The globals argument is only used to determine the context;\n\
+they are not modified. The locals argument is unused. The fromlist\n\
+should be a list of names to emulate ``from name import ...'', or an\n\
+empty list to emulate ``import name''.\n\
+When importing a module from a package, note that __import__('A.B', ...)\n\
+returns package A when fromlist is empty, but its submodule B when\n\
+fromlist is not empty. The level argument is used to determine whether to\n\
+perform absolute or relative imports: 0 is absolute, while a positive number\n\
+is the number of parent directories to search relative to the current module.");
+
+
+static PyObject *
+builtin_abs(PyObject *self, PyObject *v)
+{
+ return PyNumber_Absolute(v);
+}
+
+PyDoc_STRVAR(abs_doc,
+"abs(number) -> number\n\
+\n\
+Return the absolute value of the argument.");
+
+static PyObject *
+builtin_all(PyObject *self, PyObject *v)
+{
+ PyObject *it, *item;
+ PyObject *(*iternext)(PyObject *);
+ int cmp;
+
+ it = PyObject_GetIter(v);
+ if (it == NULL)
+ return NULL;
+ iternext = *Py_TYPE(it)->tp_iternext;
+
+ for (;;) {
+ item = iternext(it);
+ if (item == NULL)
+ break;
+ cmp = PyObject_IsTrue(item);
+ Py_DECREF(item);
+ if (cmp < 0) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ if (cmp == 0) {
+ Py_DECREF(it);
+ Py_RETURN_FALSE;
+ }
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ else
+ return NULL;
+ }
+ Py_RETURN_TRUE;
+}
+
+PyDoc_STRVAR(all_doc,
+"all(iterable) -> bool\n\
+\n\
+Return True if bool(x) is True for all values x in the iterable.\n\
+If the iterable is empty, return True.");
+
+static PyObject *
+builtin_any(PyObject *self, PyObject *v)
+{
+ PyObject *it, *item;
+ PyObject *(*iternext)(PyObject *);
+ int cmp;
+
+ it = PyObject_GetIter(v);
+ if (it == NULL)
+ return NULL;
+ iternext = *Py_TYPE(it)->tp_iternext;
+
+ for (;;) {
+ item = iternext(it);
+ if (item == NULL)
+ break;
+ cmp = PyObject_IsTrue(item);
+ Py_DECREF(item);
+ if (cmp < 0) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ if (cmp == 1) {
+ Py_DECREF(it);
+ Py_RETURN_TRUE;
+ }
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ else
+ return NULL;
+ }
+ Py_RETURN_FALSE;
+}
+
+PyDoc_STRVAR(any_doc,
+"any(iterable) -> bool\n\
+\n\
+Return True if bool(x) is True for any x in the iterable.\n\
+If the iterable is empty, return False.");
+
+static PyObject *
+builtin_apply(PyObject *self, PyObject *args)
+{
+ PyObject *func, *alist = NULL, *kwdict = NULL;
+ PyObject *t = NULL, *retval = NULL;
+
+ if (PyErr_WarnPy3k("apply() not supported in 3.x; "
+ "use func(*args, **kwargs)", 1) < 0)
+ return NULL;
+
+ if (!PyArg_UnpackTuple(args, "apply", 1, 3, &func, &alist, &kwdict))
+ return NULL;
+ if (alist != NULL) {
+ if (!PyTuple_Check(alist)) {
+ if (!PySequence_Check(alist)) {
+ PyErr_Format(PyExc_TypeError,
+ "apply() arg 2 expected sequence, found %s",
+ alist->ob_type->tp_name);
+ return NULL;
+ }
+ t = PySequence_Tuple(alist);
+ if (t == NULL)
+ return NULL;
+ alist = t;
+ }
+ }
+ if (kwdict != NULL && !PyDict_Check(kwdict)) {
+ PyErr_Format(PyExc_TypeError,
+ "apply() arg 3 expected dictionary, found %s",
+ kwdict->ob_type->tp_name);
+ goto finally;
+ }
+ retval = PyEval_CallObjectWithKeywords(func, alist, kwdict);
+ finally:
+ Py_XDECREF(t);
+ return retval;
+}
+
+PyDoc_STRVAR(apply_doc,
+"apply(object[, args[, kwargs]]) -> value\n\
+\n\
+Call a callable object with positional arguments taken from the tuple args,\n\
+and keyword arguments taken from the optional dictionary kwargs.\n\
+Note that classes are callable, as are instances with a __call__() method.\n\
+\n\
+Deprecated since release 2.3. Instead, use the extended call syntax:\n\
+ function(*args, **keywords).");
+
+
+static PyObject *
+builtin_bin(PyObject *self, PyObject *v)
+{
+ return PyNumber_ToBase(v, 2);
+}
+
+PyDoc_STRVAR(bin_doc,
+"bin(number) -> string\n\
+\n\
+Return the binary representation of an integer or long integer.");
+
+
+static PyObject *
+builtin_callable(PyObject *self, PyObject *v)
+{
+ return PyBool_FromLong((long)PyCallable_Check(v));
+}
+
+PyDoc_STRVAR(callable_doc,
+"callable(object) -> bool\n\
+\n\
+Return whether the object is callable (i.e., some kind of function).\n\
+Note that classes are callable, as are instances with a __call__() method.");
+
+
+static PyObject *
+builtin_filter(PyObject *self, PyObject *args)
+{
+ PyObject *func, *seq, *result, *it, *arg;
+ Py_ssize_t len; /* guess for result list size */
+ register Py_ssize_t j;
+
+ if (!PyArg_UnpackTuple(args, "filter", 2, 2, &func, &seq))
+ return NULL;
+
+ /* Strings and tuples return a result of the same type. */
+ if (PyString_Check(seq))
+ return filterstring(func, seq);
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(seq))
+ return filterunicode(func, seq);
+#endif
+ if (PyTuple_Check(seq))
+ return filtertuple(func, seq);
+
+ /* Pre-allocate argument list tuple. */
+ arg = PyTuple_New(1);
+ if (arg == NULL)
+ return NULL;
+
+ /* Get iterator. */
+ it = PyObject_GetIter(seq);
+ if (it == NULL)
+ goto Fail_arg;
+
+ /* Guess a result list size. */
+ len = _PyObject_LengthHint(seq, 8);
+ if (len == -1)
+ goto Fail_it;
+
+ /* Get a result list. */
+ if (PyList_Check(seq) && seq->ob_refcnt == 1) {
+ /* Eww - can modify the list in-place. */
+ Py_INCREF(seq);
+ result = seq;
+ }
+ else {
+ result = PyList_New(len);
+ if (result == NULL)
+ goto Fail_it;
+ }
+
+ /* Build the result list. */
+ j = 0;
+ for (;;) {
+ PyObject *item;
+ int ok;
+
+ item = PyIter_Next(it);
+ if (item == NULL) {
+ if (PyErr_Occurred())
+ goto Fail_result_it;
+ break;
+ }
+
+ if (func == (PyObject *)&PyBool_Type || func == Py_None) {
+ ok = PyObject_IsTrue(item);
+ }
+ else {
+ PyObject *good;
+ PyTuple_SET_ITEM(arg, 0, item);
+ good = PyObject_Call(func, arg, NULL);
+ PyTuple_SET_ITEM(arg, 0, NULL);
+ if (good == NULL) {
+ Py_DECREF(item);
+ goto Fail_result_it;
+ }
+ ok = PyObject_IsTrue(good);
+ Py_DECREF(good);
+ }
+ if (ok > 0) {
+ if (j < len)
+ PyList_SET_ITEM(result, j, item);
+ else {
+ int status = PyList_Append(result, item);
+ Py_DECREF(item);
+ if (status < 0)
+ goto Fail_result_it;
+ }
+ ++j;
+ }
+ else {
+ Py_DECREF(item);
+ if (ok < 0)
+ goto Fail_result_it;
+ }
+ }
+
+
+ /* Cut back result list if len is too big. */
+ if (j < len && PyList_SetSlice(result, j, len, NULL) < 0)
+ goto Fail_result_it;
+
+ Py_DECREF(it);
+ Py_DECREF(arg);
+ return result;
+
+Fail_result_it:
+ Py_DECREF(result);
+Fail_it:
+ Py_DECREF(it);
+Fail_arg:
+ Py_DECREF(arg);
+ return NULL;
+}
+
+PyDoc_STRVAR(filter_doc,
+"filter(function or None, sequence) -> list, tuple, or string\n"
+"\n"
+"Return those items of sequence for which function(item) is true. If\n"
+"function is None, return the items that are true. If sequence is a tuple\n"
+"or string, return the same type, else return a list.");
+
+static PyObject *
+builtin_format(PyObject *self, PyObject *args)
+{
+ PyObject *value;
+ PyObject *format_spec = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|O:format", &value, &format_spec))
+ return NULL;
+
+ return PyObject_Format(value, format_spec);
+}
+
+PyDoc_STRVAR(format_doc,
+"format(value[, format_spec]) -> string\n\
+\n\
+Returns value.__format__(format_spec)\n\
+format_spec defaults to the empty string.\n\
+See the Format Specification Mini-Language section of help('FORMATTING') for\n\
+details.");
+
+static PyObject *
+builtin_chr(PyObject *self, PyObject *args)
+{
+ long x;
+ char s[1];
+
+ if (!PyArg_ParseTuple(args, "l:chr", &x))
+ return NULL;
+ if (x < 0 || x >= 256) {
+ PyErr_SetString(PyExc_ValueError,
+ "chr() arg not in range(256)");
+ return NULL;
+ }
+ s[0] = (char)x;
+ return PyString_FromStringAndSize(s, 1);
+}
+
+PyDoc_STRVAR(chr_doc,
+"chr(i) -> character\n\
+\n\
+Return a string of one character with ordinal i; 0 <= i < 256.");
+
+
+#ifdef Py_USING_UNICODE
+static PyObject *
+builtin_unichr(PyObject *self, PyObject *args)
+{
+ int x;
+
+ if (!PyArg_ParseTuple(args, "i:unichr", &x))
+ return NULL;
+
+ return PyUnicode_FromOrdinal(x);
+}
+
+PyDoc_STRVAR(unichr_doc,
+"unichr(i) -> Unicode character\n\
+\n\
+Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff.");
+#endif
+
+
+static PyObject *
+builtin_cmp(PyObject *self, PyObject *args)
+{
+ PyObject *a, *b;
+ int c;
+
+ if (!PyArg_UnpackTuple(args, "cmp", 2, 2, &a, &b))
+ return NULL;
+ if (PyObject_Cmp(a, b, &c) < 0)
+ return NULL;
+ return PyInt_FromLong((long)c);
+}
+
+PyDoc_STRVAR(cmp_doc,
+"cmp(x, y) -> integer\n\
+\n\
+Return negative if x<y, zero if x==y, positive if x>y.");
+
+
+static PyObject *
+builtin_coerce(PyObject *self, PyObject *args)
+{
+ PyObject *v, *w;
+ PyObject *res;
+
+ if (PyErr_WarnPy3k("coerce() not supported in 3.x", 1) < 0)
+ return NULL;
+
+ if (!PyArg_UnpackTuple(args, "coerce", 2, 2, &v, &w))
+ return NULL;
+ if (PyNumber_Coerce(&v, &w) < 0)
+ return NULL;
+ res = PyTuple_Pack(2, v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ return res;
+}
+
+PyDoc_STRVAR(coerce_doc,
+"coerce(x, y) -> (x1, y1)\n\
+\n\
+Return a tuple consisting of the two numeric arguments converted to\n\
+a common type, using the same rules as used by arithmetic operations.\n\
+If coercion is not possible, raise TypeError.");
+
+static PyObject *
+builtin_compile(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ char *str;
+ char *filename;
+ char *startstr;
+ int mode = -1;
+ int dont_inherit = 0;
+ int supplied_flags = 0;
+ int is_ast;
+ PyCompilerFlags cf;
+ PyObject *result = NULL, *cmd, *tmp = NULL;
+ Py_ssize_t length;
+ static char *kwlist[] = {"source", "filename", "mode", "flags",
+ "dont_inherit", NULL};
+ int start[] = {Py_file_input, Py_eval_input, Py_single_input};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oss|ii:compile",
+ kwlist, &cmd, &filename, &startstr,
+ &supplied_flags, &dont_inherit))
+ return NULL;
+
+ cf.cf_flags = supplied_flags;
+
+ if (supplied_flags &
+ ~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_DONT_IMPLY_DEDENT | PyCF_ONLY_AST))
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "compile(): unrecognised flags");
+ return NULL;
+ }
+ /* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */
+
+ if (!dont_inherit) {
+ PyEval_MergeCompilerFlags(&cf);
+ }
+
+ if (strcmp(startstr, "exec") == 0)
+ mode = 0;
+ else if (strcmp(startstr, "eval") == 0)
+ mode = 1;
+ else if (strcmp(startstr, "single") == 0)
+ mode = 2;
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "compile() arg 3 must be 'exec', 'eval' or 'single'");
+ return NULL;
+ }
+
+ is_ast = PyAST_Check(cmd);
+ if (is_ast == -1)
+ return NULL;
+ if (is_ast) {
+ if (supplied_flags & PyCF_ONLY_AST) {
+ Py_INCREF(cmd);
+ result = cmd;
+ }
+ else {
+ PyArena *arena;
+ mod_ty mod;
+
+ arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+ mod = PyAST_obj2mod(cmd, arena, mode);
+ if (mod == NULL) {
+ PyArena_Free(arena);
+ return NULL;
+ }
+ result = (PyObject*)PyAST_Compile(mod, filename,
+ &cf, arena);
+ PyArena_Free(arena);
+ }
+ return result;
+ }
+ if (PyString_Check(cmd)) {
+ str = PyString_AS_STRING(cmd);
+ length = PyString_GET_SIZE(cmd);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(cmd)) {
+ tmp = PyUnicode_AsUTF8String(cmd);
+ if (tmp == NULL)
+ return NULL;
+ cf.cf_flags |= PyCF_SOURCE_IS_UTF8;
+ str = PyString_AS_STRING(tmp);
+ length = PyString_GET_SIZE(tmp);
+ }
+#endif
+ else if (!PyObject_AsReadBuffer(cmd, (const void **)&str, &length)) {
+ /* Copy to NUL-terminated buffer. */
+ tmp = PyString_FromStringAndSize(str, length);
+ if (tmp == NULL)
+ return NULL;
+ str = PyString_AS_STRING(tmp);
+ length = PyString_GET_SIZE(tmp);
+ }
+ else
+ goto cleanup;
+ if ((size_t)length != strlen(str)) {
+ PyErr_SetString(PyExc_TypeError,
+ "compile() expected string without null bytes");
+ goto cleanup;
+ }
+ result = Py_CompileStringFlags(str, filename, start[mode], &cf);
+cleanup:
+ Py_XDECREF(tmp);
+ return result;
+}
+
+PyDoc_STRVAR(compile_doc,
+"compile(source, filename, mode[, flags[, dont_inherit]]) -> code object\n\
+\n\
+Compile the source string (a Python module, statement or expression)\n\
+into a code object that can be executed by the exec statement or eval().\n\
+The filename will be used for run-time error messages.\n\
+The mode must be 'exec' to compile a module, 'single' to compile a\n\
+single (interactive) statement, or 'eval' to compile an expression.\n\
+The flags argument, if present, controls which future statements influence\n\
+the compilation of the code.\n\
+The dont_inherit argument, if non-zero, stops the compilation inheriting\n\
+the effects of any future statements in effect in the code calling\n\
+compile; if absent or zero these statements do influence the compilation,\n\
+in addition to any features explicitly specified.");
+
+static PyObject *
+builtin_dir(PyObject *self, PyObject *args)
+{
+ PyObject *arg = NULL;
+
+ if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg))
+ return NULL;
+ return PyObject_Dir(arg);
+}
+
+PyDoc_STRVAR(dir_doc,
+"dir([object]) -> list of strings\n"
+"\n"
+"If called without an argument, return the names in the current scope.\n"
+"Else, return an alphabetized list of names comprising (some of) the attributes\n"
+"of the given object, and of attributes reachable from it.\n"
+"If the object supplies a method named __dir__, it will be used; otherwise\n"
+"the default dir() logic is used and returns:\n"
+" for a module object: the module's attributes.\n"
+" for a class object: its attributes, and recursively the attributes\n"
+" of its bases.\n"
+" for any other object: its attributes, its class's attributes, and\n"
+" recursively the attributes of its class's base classes.");
+
+static PyObject *
+builtin_divmod(PyObject *self, PyObject *args)
+{
+ PyObject *v, *w;
+
+ if (!PyArg_UnpackTuple(args, "divmod", 2, 2, &v, &w))
+ return NULL;
+ return PyNumber_Divmod(v, w);
+}
+
+PyDoc_STRVAR(divmod_doc,
+"divmod(x, y) -> (quotient, remainder)\n\
+\n\
+Return the tuple (x//y, x%y). Invariant: div*y + mod == x.");
+
+
+static PyObject *
+builtin_eval(PyObject *self, PyObject *args)
+{
+ PyObject *cmd, *result, *tmp = NULL;
+ PyObject *globals = Py_None, *locals = Py_None;
+ char *str;
+ PyCompilerFlags cf;
+
+ if (!PyArg_UnpackTuple(args, "eval", 1, 3, &cmd, &globals, &locals))
+ return NULL;
+ if (locals != Py_None && !PyMapping_Check(locals)) {
+ PyErr_SetString(PyExc_TypeError, "locals must be a mapping");
+ return NULL;
+ }
+ if (globals != Py_None && !PyDict_Check(globals)) {
+ PyErr_SetString(PyExc_TypeError, PyMapping_Check(globals) ?
+ "globals must be a real dict; try eval(expr, {}, mapping)"
+ : "globals must be a dict");
+ return NULL;
+ }
+ if (globals == Py_None) {
+ globals = PyEval_GetGlobals();
+ if (locals == Py_None)
+ locals = PyEval_GetLocals();
+ }
+ else if (locals == Py_None)
+ locals = globals;
+
+ if (globals == NULL || locals == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "eval must be given globals and locals "
+ "when called without a frame");
+ return NULL;
+ }
+
+ if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
+ if (PyDict_SetItemString(globals, "__builtins__",
+ PyEval_GetBuiltins()) != 0)
+ return NULL;
+ }
+
+ if (PyCode_Check(cmd)) {
+ if (PyCode_GetNumFree((PyCodeObject *)cmd) > 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "code object passed to eval() may not contain free variables");
+ return NULL;
+ }
+ return PyEval_EvalCode((PyCodeObject *) cmd, globals, locals);
+ }
+
+ if (!PyString_Check(cmd) &&
+ !PyUnicode_Check(cmd)) {
+ PyErr_SetString(PyExc_TypeError,
+ "eval() arg 1 must be a string or code object");
+ return NULL;
+ }
+ cf.cf_flags = 0;
+
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(cmd)) {
+ tmp = PyUnicode_AsUTF8String(cmd);
+ if (tmp == NULL)
+ return NULL;
+ cmd = tmp;
+ cf.cf_flags |= PyCF_SOURCE_IS_UTF8;
+ }
+#endif
+ if (PyString_AsStringAndSize(cmd, &str, NULL)) {
+ Py_XDECREF(tmp);
+ return NULL;
+ }
+ while (*str == ' ' || *str == '\t')
+ str++;
+
+ (void)PyEval_MergeCompilerFlags(&cf);
+ result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf);
+ Py_XDECREF(tmp);
+ return result;
+}
+
+PyDoc_STRVAR(eval_doc,
+"eval(source[, globals[, locals]]) -> value\n\
+\n\
+Evaluate the source in the context of globals and locals.\n\
+The source may be a string representing a Python expression\n\
+or a code object as returned by compile().\n\
+The globals must be a dictionary and locals can be any mapping,\n\
+defaulting to the current globals and locals.\n\
+If only globals is given, locals defaults to it.\n");
+
+
+static PyObject *
+builtin_execfile(PyObject *self, PyObject *args)
+{
+ char *filename;
+ PyObject *globals = Py_None, *locals = Py_None;
+ PyObject *res;
+ FILE* fp = NULL;
+ PyCompilerFlags cf;
+ int exists;
+
+ if (PyErr_WarnPy3k("execfile() not supported in 3.x; use exec()",
+ 1) < 0)
+ return NULL;
+
+ if (!PyArg_ParseTuple(args, "s|O!O:execfile",
+ &filename,
+ &PyDict_Type, &globals,
+ &locals))
+ return NULL;
+ if (locals != Py_None && !PyMapping_Check(locals)) {
+ PyErr_SetString(PyExc_TypeError, "locals must be a mapping");
+ return NULL;
+ }
+ if (globals == Py_None) {
+ globals = PyEval_GetGlobals();
+ if (locals == Py_None)
+ locals = PyEval_GetLocals();
+ }
+ else if (locals == Py_None)
+ locals = globals;
+ if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
+ if (PyDict_SetItemString(globals, "__builtins__",
+ PyEval_GetBuiltins()) != 0)
+ return NULL;
+ }
+
+ exists = 0;
+ /* Test for existence or directory. */
+#if defined(PLAN9)
+ {
+ Dir *d;
+
+ if ((d = dirstat(filename))!=nil) {
+ if(d->mode & DMDIR)
+ werrstr("is a directory");
+ else
+ exists = 1;
+ free(d);
+ }
+ }
+#elif defined(RISCOS)
+ if (object_exists(filename)) {
+ if (isdir(filename))
+ errno = EISDIR;
+ else
+ exists = 1;
+ }
+#else /* standard Posix */
+ {
+ struct stat s;
+ if (stat(filename, &s) == 0) {
+ if (S_ISDIR(s.st_mode))
+# if defined(PYOS_OS2) && defined(PYCC_VACPP)
+ errno = EOS2ERR;
+# else
+ errno = EISDIR;
+# endif
+ else
+ exists = 1;
+ }
+ }
+#endif
+
+ if (exists) {
+ Py_BEGIN_ALLOW_THREADS
+ fp = fopen(filename, "r" PY_STDIOTEXTMODE);
+ Py_END_ALLOW_THREADS
+
+ if (fp == NULL) {
+ exists = 0;
+ }
+ }
+
+ if (!exists) {
+ PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
+ return NULL;
+ }
+ cf.cf_flags = 0;
+ if (PyEval_MergeCompilerFlags(&cf))
+ res = PyRun_FileExFlags(fp, filename, Py_file_input, globals,
+ locals, 1, &cf);
+ else
+ res = PyRun_FileEx(fp, filename, Py_file_input, globals,
+ locals, 1);
+ return res;
+}
+
+PyDoc_STRVAR(execfile_doc,
+"execfile(filename[, globals[, locals]])\n\
+\n\
+Read and execute a Python script from a file.\n\
+The globals and locals are dictionaries, defaulting to the current\n\
+globals and locals. If only globals is given, locals defaults to it.");
+
+
+static PyObject *
+builtin_getattr(PyObject *self, PyObject *args)
+{
+ PyObject *v, *result, *dflt = NULL;
+ PyObject *name;
+
+ if (!PyArg_UnpackTuple(args, "getattr", 2, 3, &v, &name, &dflt))
+ return NULL;
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(name)) {
+ name = _PyUnicode_AsDefaultEncodedString(name, NULL);
+ if (name == NULL)
+ return NULL;
+ }
+#endif
+
+ if (!PyString_Check(name)) {
+ PyErr_SetString(PyExc_TypeError,
+ "getattr(): attribute name must be string");
+ return NULL;
+ }
+ result = PyObject_GetAttr(v, name);
+ if (result == NULL && dflt != NULL &&
+ PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ PyErr_Clear();
+ Py_INCREF(dflt);
+ result = dflt;
+ }
+ return result;
+}
+
+PyDoc_STRVAR(getattr_doc,
+"getattr(object, name[, default]) -> value\n\
+\n\
+Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.\n\
+When a default argument is given, it is returned when the attribute doesn't\n\
+exist; without it, an exception is raised in that case.");
+
+
+static PyObject *
+builtin_globals(PyObject *self)
+{
+ PyObject *d;
+
+ d = PyEval_GetGlobals();
+ Py_XINCREF(d);
+ return d;
+}
+
+PyDoc_STRVAR(globals_doc,
+"globals() -> dictionary\n\
+\n\
+Return the dictionary containing the current scope's global variables.");
+
+
+static PyObject *
+builtin_hasattr(PyObject *self, PyObject *args)
+{
+ PyObject *v;
+ PyObject *name;
+
+ if (!PyArg_UnpackTuple(args, "hasattr", 2, 2, &v, &name))
+ return NULL;
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(name)) {
+ name = _PyUnicode_AsDefaultEncodedString(name, NULL);
+ if (name == NULL)
+ return NULL;
+ }
+#endif
+
+ if (!PyString_Check(name)) {
+ PyErr_SetString(PyExc_TypeError,
+ "hasattr(): attribute name must be string");
+ return NULL;
+ }
+ v = PyObject_GetAttr(v, name);
+ if (v == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_Exception))
+ return NULL;
+ else {
+ PyErr_Clear();
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ }
+ Py_DECREF(v);
+ Py_INCREF(Py_True);
+ return Py_True;
+}
+
+PyDoc_STRVAR(hasattr_doc,
+"hasattr(object, name) -> bool\n\
+\n\
+Return whether the object has an attribute with the given name.\n\
+(This is done by calling getattr(object, name) and catching exceptions.)");
+
+
+static PyObject *
+builtin_id(PyObject *self, PyObject *v)
+{
+ return PyLong_FromVoidPtr(v);
+}
+
+PyDoc_STRVAR(id_doc,
+"id(object) -> integer\n\
+\n\
+Return the identity of an object. This is guaranteed to be unique among\n\
+simultaneously existing objects. (Hint: it's the object's memory address.)");
+
+
+static PyObject *
+builtin_map(PyObject *self, PyObject *args)
+{
+ typedef struct {
+ PyObject *it; /* the iterator object */
+ int saw_StopIteration; /* bool: did the iterator end? */
+ } sequence;
+
+ PyObject *func, *result;
+ sequence *seqs = NULL, *sqp;
+ Py_ssize_t n, len;
+ register int i, j;
+
+ n = PyTuple_Size(args);
+ if (n < 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "map() requires at least two args");
+ return NULL;
+ }
+
+ func = PyTuple_GetItem(args, 0);
+ n--;
+
+ if (func == Py_None) {
+ if (PyErr_WarnPy3k("map(None, ...) not supported in 3.x; "
+ "use list(...)", 1) < 0)
+ return NULL;
+ if (n == 1) {
+ /* map(None, S) is the same as list(S). */
+ return PySequence_List(PyTuple_GetItem(args, 1));
+ }
+ }
+
+ /* Get space for sequence descriptors. Must NULL out the iterator
+ * pointers so that jumping to Fail_2 later doesn't see trash.
+ */
+ if ((seqs = PyMem_NEW(sequence, n)) == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i = 0; i < n; ++i) {
+ seqs[i].it = (PyObject*)NULL;
+ seqs[i].saw_StopIteration = 0;
+ }
+
+ /* Do a first pass to obtain iterators for the arguments, and set len
+ * to the largest of their lengths.
+ */
+ len = 0;
+ for (i = 0, sqp = seqs; i < n; ++i, ++sqp) {
+ PyObject *curseq;
+ Py_ssize_t curlen;
+
+ /* Get iterator. */
+ curseq = PyTuple_GetItem(args, i+1);
+ sqp->it = PyObject_GetIter(curseq);
+ if (sqp->it == NULL) {
+ static char errmsg[] =
+ "argument %d to map() must support iteration";
+ char errbuf[sizeof(errmsg) + 25];
+ PyOS_snprintf(errbuf, sizeof(errbuf), errmsg, i+2);
+ PyErr_SetString(PyExc_TypeError, errbuf);
+ goto Fail_2;
+ }
+
+ /* Update len. */
+ curlen = _PyObject_LengthHint(curseq, 8);
+ if (curlen > len)
+ len = curlen;
+ }
+
+ /* Get space for the result list. */
+ if ((result = (PyObject *) PyList_New(len)) == NULL)
+ goto Fail_2;
+
+ /* Iterate over the sequences until all have stopped. */
+ for (i = 0; ; ++i) {
+ PyObject *alist, *item=NULL, *value;
+ int numactive = 0;
+
+ if (func == Py_None && n == 1)
+ alist = NULL;
+ else if ((alist = PyTuple_New(n)) == NULL)
+ goto Fail_1;
+
+ for (j = 0, sqp = seqs; j < n; ++j, ++sqp) {
+ if (sqp->saw_StopIteration) {
+ Py_INCREF(Py_None);
+ item = Py_None;
+ }
+ else {
+ item = PyIter_Next(sqp->it);
+ if (item)
+ ++numactive;
+ else {
+ if (PyErr_Occurred()) {
+ Py_XDECREF(alist);
+ goto Fail_1;
+ }
+ Py_INCREF(Py_None);
+ item = Py_None;
+ sqp->saw_StopIteration = 1;
+ }
+ }
+ if (alist)
+ PyTuple_SET_ITEM(alist, j, item);
+ else
+ break;
+ }
+
+ if (!alist)
+ alist = item;
+
+ if (numactive == 0) {
+ Py_DECREF(alist);
+ break;
+ }
+
+ if (func == Py_None)
+ value = alist;
+ else {
+ value = PyEval_CallObject(func, alist);
+ Py_DECREF(alist);
+ if (value == NULL)
+ goto Fail_1;
+ }
+ if (i >= len) {
+ int status = PyList_Append(result, value);
+ Py_DECREF(value);
+ if (status < 0)
+ goto Fail_1;
+ }
+ else if (PyList_SetItem(result, i, value) < 0)
+ goto Fail_1;
+ }
+
+ if (i < len && PyList_SetSlice(result, i, len, NULL) < 0)
+ goto Fail_1;
+
+ goto Succeed;
+
+Fail_1:
+ Py_DECREF(result);
+Fail_2:
+ result = NULL;
+Succeed:
+ assert(seqs);
+ for (i = 0; i < n; ++i)
+ Py_XDECREF(seqs[i].it);
+ PyMem_DEL(seqs);
+ return result;
+}
+
+PyDoc_STRVAR(map_doc,
+"map(function, sequence[, sequence, ...]) -> list\n\
+\n\
+Return a list of the results of applying the function to the items of\n\
+the argument sequence(s). If more than one sequence is given, the\n\
+function is called with an argument list consisting of the corresponding\n\
+item of each sequence, substituting None for missing values when not all\n\
+sequences have the same length. If the function is None, return a list of\n\
+the items of the sequence (or a list of tuples if more than one sequence).");
+
+
+static PyObject *
+builtin_next(PyObject *self, PyObject *args)
+{
+ PyObject *it, *res;
+ PyObject *def = NULL;
+
+ if (!PyArg_UnpackTuple(args, "next", 1, 2, &it, &def))
+ return NULL;
+ if (!PyIter_Check(it)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s object is not an iterator",
+ it->ob_type->tp_name);
+ return NULL;
+ }
+
+ res = (*it->ob_type->tp_iternext)(it);
+ if (res != NULL) {
+ return res;
+ } else if (def != NULL) {
+ if (PyErr_Occurred()) {
+ if (!PyErr_ExceptionMatches(PyExc_StopIteration))
+ return NULL;
+ PyErr_Clear();
+ }
+ Py_INCREF(def);
+ return def;
+ } else if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+}
+
+PyDoc_STRVAR(next_doc,
+"next(iterator[, default])\n\
+\n\
+Return the next item from the iterator. If default is given and the iterator\n\
+is exhausted, it is returned instead of raising StopIteration.");
+
+
+static PyObject *
+builtin_setattr(PyObject *self, PyObject *args)
+{
+ PyObject *v;
+ PyObject *name;
+ PyObject *value;
+
+ if (!PyArg_UnpackTuple(args, "setattr", 3, 3, &v, &name, &value))
+ return NULL;
+ if (PyObject_SetAttr(v, name, value) != 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setattr_doc,
+"setattr(object, name, value)\n\
+\n\
+Set a named attribute on an object; setattr(x, 'y', v) is equivalent to\n\
+``x.y = v''.");
+
+
+static PyObject *
+builtin_delattr(PyObject *self, PyObject *args)
+{
+ PyObject *v;
+ PyObject *name;
+
+ if (!PyArg_UnpackTuple(args, "delattr", 2, 2, &v, &name))
+ return NULL;
+ if (PyObject_SetAttr(v, name, (PyObject *)NULL) != 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(delattr_doc,
+"delattr(object, name)\n\
+\n\
+Delete a named attribute on an object; delattr(x, 'y') is equivalent to\n\
+``del x.y''.");
+
+
+static PyObject *
+builtin_hash(PyObject *self, PyObject *v)
+{
+ long x;
+
+ x = PyObject_Hash(v);
+ if (x == -1)
+ return NULL;
+ return PyInt_FromLong(x);
+}
+
+PyDoc_STRVAR(hash_doc,
+"hash(object) -> integer\n\
+\n\
+Return a hash value for the object. Two objects with the same value have\n\
+the same hash value. The reverse is not necessarily true, but likely.");
+
+
+static PyObject *
+builtin_hex(PyObject *self, PyObject *v)
+{
+ PyNumberMethods *nb;
+ PyObject *res;
+
+ if ((nb = v->ob_type->tp_as_number) == NULL ||
+ nb->nb_hex == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "hex() argument can't be converted to hex");
+ return NULL;
+ }
+ res = (*nb->nb_hex)(v);
+ if (res && !PyString_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "__hex__ returned non-string (type %.200s)",
+ res->ob_type->tp_name);
+ Py_DECREF(res);
+ return NULL;
+ }
+ return res;
+}
+
+PyDoc_STRVAR(hex_doc,
+"hex(number) -> string\n\
+\n\
+Return the hexadecimal representation of an integer or long integer.");
+
+
+static PyObject *builtin_raw_input(PyObject *, PyObject *);
+
+static PyObject *
+builtin_input(PyObject *self, PyObject *args)
+{
+ PyObject *line;
+ char *str;
+ PyObject *res;
+ PyObject *globals, *locals;
+ PyCompilerFlags cf;
+
+ line = builtin_raw_input(self, args);
+ if (line == NULL)
+ return line;
+ if (!PyArg_Parse(line, "s;embedded '\\0' in input line", &str))
+ return NULL;
+ while (*str == ' ' || *str == '\t')
+ str++;
+ globals = PyEval_GetGlobals();
+ locals = PyEval_GetLocals();
+ if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
+ if (PyDict_SetItemString(globals, "__builtins__",
+ PyEval_GetBuiltins()) != 0)
+ return NULL;
+ }
+ cf.cf_flags = 0;
+ PyEval_MergeCompilerFlags(&cf);
+ res = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf);
+ Py_DECREF(line);
+ return res;
+}
+
+PyDoc_STRVAR(input_doc,
+"input([prompt]) -> value\n\
+\n\
+Equivalent to eval(raw_input(prompt)).");
+
+
+static PyObject *
+builtin_intern(PyObject *self, PyObject *args)
+{
+ PyObject *s;
+ if (!PyArg_ParseTuple(args, "S:intern", &s))
+ return NULL;
+ if (!PyString_CheckExact(s)) {
+ PyErr_SetString(PyExc_TypeError,
+ "can't intern subclass of string");
+ return NULL;
+ }
+ Py_INCREF(s);
+ PyString_InternInPlace(&s);
+ return s;
+}
+
+PyDoc_STRVAR(intern_doc,
+"intern(string) -> string\n\
+\n\
+``Intern'' the given string. This enters the string in the (global)\n\
+table of interned strings whose purpose is to speed up dictionary lookups.\n\
+Return the string itself or the previously interned string object with the\n\
+same value.");
+
+
+static PyObject *
+builtin_iter(PyObject *self, PyObject *args)
+{
+ PyObject *v, *w = NULL;
+
+ if (!PyArg_UnpackTuple(args, "iter", 1, 2, &v, &w))
+ return NULL;
+ if (w == NULL)
+ return PyObject_GetIter(v);
+ if (!PyCallable_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "iter(v, w): v must be callable");
+ return NULL;
+ }
+ return PyCallIter_New(v, w);
+}
+
+PyDoc_STRVAR(iter_doc,
+"iter(collection) -> iterator\n\
+iter(callable, sentinel) -> iterator\n\
+\n\
+Get an iterator from an object. In the first form, the argument must\n\
+supply its own iterator, or be a sequence.\n\
+In the second form, the callable is called until it returns the sentinel.");
+
+
+static PyObject *
+builtin_len(PyObject *self, PyObject *v)
+{
+ Py_ssize_t res;
+
+ res = PyObject_Size(v);
+ if (res < 0 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromSsize_t(res);
+}
+
+PyDoc_STRVAR(len_doc,
+"len(object) -> integer\n\
+\n\
+Return the number of items of a sequence or collection.");
+
+
+static PyObject *
+builtin_locals(PyObject *self)
+{
+ PyObject *d;
+
+ d = PyEval_GetLocals();
+ Py_XINCREF(d);
+ return d;
+}
+
+PyDoc_STRVAR(locals_doc,
+"locals() -> dictionary\n\
+\n\
+Update and return a dictionary containing the current scope's local variables.");
+
+
+static PyObject *
+min_max(PyObject *args, PyObject *kwds, int op)
+{
+ PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
+ const char *name = op == Py_LT ? "min" : "max";
+
+ if (PyTuple_Size(args) > 1)
+ v = args;
+ else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v))
+ return NULL;
+
+ if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) {
+ keyfunc = PyDict_GetItemString(kwds, "key");
+ if (PyDict_Size(kwds)!=1 || keyfunc == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%s() got an unexpected keyword argument", name);
+ return NULL;
+ }
+ Py_INCREF(keyfunc);
+ }
+
+ it = PyObject_GetIter(v);
+ if (it == NULL) {
+ Py_XDECREF(keyfunc);
+ return NULL;
+ }
+
+ maxitem = NULL; /* the result */
+ maxval = NULL; /* the value associated with the result */
+ while (( item = PyIter_Next(it) )) {
+ /* get the value from the key function */
+ if (keyfunc != NULL) {
+ val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
+ if (val == NULL)
+ goto Fail_it_item;
+ }
+ /* no key function; the value is the item */
+ else {
+ val = item;
+ Py_INCREF(val);
+ }
+
+ /* maximum value and item are unset; set them */
+ if (maxval == NULL) {
+ maxitem = item;
+ maxval = val;
+ }
+ /* maximum value and item are set; update them as necessary */
+ else {
+ int cmp = PyObject_RichCompareBool(val, maxval, op);
+ if (cmp < 0)
+ goto Fail_it_item_and_val;
+ else if (cmp > 0) {
+ Py_DECREF(maxval);
+ Py_DECREF(maxitem);
+ maxval = val;
+ maxitem = item;
+ }
+ else {
+ Py_DECREF(item);
+ Py_DECREF(val);
+ }
+ }
+ }
+ if (PyErr_Occurred())
+ goto Fail_it;
+ if (maxval == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "%s() arg is an empty sequence", name);
+ assert(maxitem == NULL);
+ }
+ else
+ Py_DECREF(maxval);
+ Py_DECREF(it);
+ Py_XDECREF(keyfunc);
+ return maxitem;
+
+Fail_it_item_and_val:
+ Py_DECREF(val);
+Fail_it_item:
+ Py_DECREF(item);
+Fail_it:
+ Py_XDECREF(maxval);
+ Py_XDECREF(maxitem);
+ Py_DECREF(it);
+ Py_XDECREF(keyfunc);
+ return NULL;
+}
+
+static PyObject *
+builtin_min(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ return min_max(args, kwds, Py_LT);
+}
+
+PyDoc_STRVAR(min_doc,
+"min(iterable[, key=func]) -> value\n\
+min(a, b, c, ...[, key=func]) -> value\n\
+\n\
+With a single iterable argument, return its smallest item.\n\
+With two or more arguments, return the smallest argument.");
+
+
+static PyObject *
+builtin_max(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ return min_max(args, kwds, Py_GT);
+}
+
+PyDoc_STRVAR(max_doc,
+"max(iterable[, key=func]) -> value\n\
+max(a, b, c, ...[, key=func]) -> value\n\
+\n\
+With a single iterable argument, return its largest item.\n\
+With two or more arguments, return the largest argument.");
+
+
+static PyObject *
+builtin_oct(PyObject *self, PyObject *v)
+{
+ PyNumberMethods *nb;
+ PyObject *res;
+
+ if (v == NULL || (nb = v->ob_type->tp_as_number) == NULL ||
+ nb->nb_oct == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "oct() argument can't be converted to oct");
+ return NULL;
+ }
+ res = (*nb->nb_oct)(v);
+ if (res && !PyString_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "__oct__ returned non-string (type %.200s)",
+ res->ob_type->tp_name);
+ Py_DECREF(res);
+ return NULL;
+ }
+ return res;
+}
+
+PyDoc_STRVAR(oct_doc,
+"oct(number) -> string\n\
+\n\
+Return the octal representation of an integer or long integer.");
+
+
+static PyObject *
+builtin_open(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ return PyObject_Call((PyObject*)&PyFile_Type, args, kwds);
+}
+
+PyDoc_STRVAR(open_doc,
+"open(name[, mode[, buffering]]) -> file object\n\
+\n\
+Open a file using the file() type, returns a file object. This is the\n\
+preferred way to open a file. See file.__doc__ for further information.");
+
+
+static PyObject *
+builtin_ord(PyObject *self, PyObject* obj)
+{
+ long ord;
+ Py_ssize_t size;
+
+ if (PyString_Check(obj)) {
+ size = PyString_GET_SIZE(obj);
+ if (size == 1) {
+ ord = (long)((unsigned char)*PyString_AS_STRING(obj));
+ return PyInt_FromLong(ord);
+ }
+ } else if (PyByteArray_Check(obj)) {
+ size = PyByteArray_GET_SIZE(obj);
+ if (size == 1) {
+ ord = (long)((unsigned char)*PyByteArray_AS_STRING(obj));
+ return PyInt_FromLong(ord);
+ }
+
+#ifdef Py_USING_UNICODE
+ } else if (PyUnicode_Check(obj)) {
+ size = PyUnicode_GET_SIZE(obj);
+ if (size == 1) {
+ ord = (long)*PyUnicode_AS_UNICODE(obj);
+ return PyInt_FromLong(ord);
+ }
+#endif
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "ord() expected string of length 1, but " \
+ "%.200s found", obj->ob_type->tp_name);
+ return NULL;
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "ord() expected a character, "
+ "but string of length %zd found",
+ size);
+ return NULL;
+}
+
+PyDoc_STRVAR(ord_doc,
+"ord(c) -> integer\n\
+\n\
+Return the integer ordinal of a one-character string.");
+
+
+static PyObject *
+builtin_pow(PyObject *self, PyObject *args)
+{
+ PyObject *v, *w, *z = Py_None;
+
+ if (!PyArg_UnpackTuple(args, "pow", 2, 3, &v, &w, &z))
+ return NULL;
+ return PyNumber_Power(v, w, z);
+}
+
+PyDoc_STRVAR(pow_doc,
+"pow(x, y[, z]) -> number\n\
+\n\
+With two arguments, equivalent to x**y. With three arguments,\n\
+equivalent to (x**y) % z, but may be more efficient (e.g. for longs).");
+
+
+static PyObject *
+builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"sep", "end", "file", 0};
+ static PyObject *dummy_args = NULL;
+ static PyObject *unicode_newline = NULL, *unicode_space = NULL;
+ static PyObject *str_newline = NULL, *str_space = NULL;
+ PyObject *newline, *space;
+ PyObject *sep = NULL, *end = NULL, *file = NULL;
+ int i, err, use_unicode = 0;
+
+ if (dummy_args == NULL) {
+ if (!(dummy_args = PyTuple_New(0)))
+ return NULL;
+ }
+ if (str_newline == NULL) {
+ str_newline = PyString_FromString("\n");
+ if (str_newline == NULL)
+ return NULL;
+ str_space = PyString_FromString(" ");
+ if (str_space == NULL) {
+ Py_CLEAR(str_newline);
+ return NULL;
+ }
+#ifdef Py_USING_UNICODE
+ unicode_newline = PyUnicode_FromString("\n");
+ if (unicode_newline == NULL) {
+ Py_CLEAR(str_newline);
+ Py_CLEAR(str_space);
+ return NULL;
+ }
+ unicode_space = PyUnicode_FromString(" ");
+ if (unicode_space == NULL) {
+ Py_CLEAR(str_newline);
+ Py_CLEAR(str_space);
+ Py_CLEAR(unicode_space);
+ return NULL;
+ }
+#endif
+ }
+ if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|OOO:print",
+ kwlist, &sep, &end, &file))
+ return NULL;
+ if (file == NULL || file == Py_None) {
+ file = PySys_GetObject("stdout");
+ /* sys.stdout may be None when FILE* stdout isn't connected */
+ if (file == Py_None)
+ Py_RETURN_NONE;
+ }
+ if (sep == Py_None) {
+ sep = NULL;
+ }
+ else if (sep) {
+ if (PyUnicode_Check(sep)) {
+ use_unicode = 1;
+ }
+ else if (!PyString_Check(sep)) {
+ PyErr_Format(PyExc_TypeError,
+ "sep must be None, str or unicode, not %.200s",
+ sep->ob_type->tp_name);
+ return NULL;
+ }
+ }
+ if (end == Py_None)
+ end = NULL;
+ else if (end) {
+ if (PyUnicode_Check(end)) {
+ use_unicode = 1;
+ }
+ else if (!PyString_Check(end)) {
+ PyErr_Format(PyExc_TypeError,
+ "end must be None, str or unicode, not %.200s",
+ end->ob_type->tp_name);
+ return NULL;
+ }
+ }
+
+ if (!use_unicode) {
+ for (i = 0; i < PyTuple_Size(args); i++) {
+ if (PyUnicode_Check(PyTuple_GET_ITEM(args, i))) {
+ use_unicode = 1;
+ break;
+ }
+ }
+ }
+ if (use_unicode) {
+ newline = unicode_newline;
+ space = unicode_space;
+ }
+ else {
+ newline = str_newline;
+ space = str_space;
+ }
+
+ for (i = 0; i < PyTuple_Size(args); i++) {
+ if (i > 0) {
+ if (sep == NULL)
+ err = PyFile_WriteObject(space, file,
+ Py_PRINT_RAW);
+ else
+ err = PyFile_WriteObject(sep, file,
+ Py_PRINT_RAW);
+ if (err)
+ return NULL;
+ }
+ err = PyFile_WriteObject(PyTuple_GetItem(args, i), file,
+ Py_PRINT_RAW);
+ if (err)
+ return NULL;
+ }
+
+ if (end == NULL)
+ err = PyFile_WriteObject(newline, file, Py_PRINT_RAW);
+ else
+ err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
+ if (err)
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(print_doc,
+"print(value, ..., sep=' ', end='\\n', file=sys.stdout)\n\
+\n\
+Prints the values to a stream, or to sys.stdout by default.\n\
+Optional keyword arguments:\n\
+file: a file-like object (stream); defaults to the current sys.stdout.\n\
+sep: string inserted between values, default a space.\n\
+end: string appended after the last value, default a newline.");
+
+
+/* Return number of items in range (lo, hi, step), when arguments are
+ * PyInt or PyLong objects. step > 0 required. Return a value < 0 if
+ * & only if the true value is too large to fit in a signed long.
+ * Arguments MUST return 1 with either PyInt_Check() or
+ * PyLong_Check(). Return -1 when there is an error.
+ */
+static long
+get_len_of_range_longs(PyObject *lo, PyObject *hi, PyObject *step)
+{
+ /* -------------------------------------------------------------
+ Algorithm is equal to that of get_len_of_range(), but it operates
+ on PyObjects (which are assumed to be PyLong or PyInt objects).
+ ---------------------------------------------------------------*/
+ long n;
+ PyObject *diff = NULL;
+ PyObject *one = NULL;
+ PyObject *tmp1 = NULL, *tmp2 = NULL, *tmp3 = NULL;
+ /* holds sub-expression evaluations */
+
+ /* if (lo >= hi), return length of 0. */
+ if (PyObject_Compare(lo, hi) >= 0)
+ return 0;
+
+ if ((one = PyLong_FromLong(1L)) == NULL)
+ goto Fail;
+
+ if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL)
+ goto Fail;
+
+ if ((diff = PyNumber_Subtract(tmp1, one)) == NULL)
+ goto Fail;
+
+ if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL)
+ goto Fail;
+
+ if ((tmp3 = PyNumber_Add(tmp2, one)) == NULL)
+ goto Fail;
+
+ n = PyLong_AsLong(tmp3);
+ if (PyErr_Occurred()) { /* Check for Overflow */
+ PyErr_Clear();
+ goto Fail;
+ }
+
+ Py_DECREF(tmp3);
+ Py_DECREF(tmp2);
+ Py_DECREF(diff);
+ Py_DECREF(tmp1);
+ Py_DECREF(one);
+ return n;
+
+ Fail:
+ Py_XDECREF(tmp3);
+ Py_XDECREF(tmp2);
+ Py_XDECREF(diff);
+ Py_XDECREF(tmp1);
+ Py_XDECREF(one);
+ return -1;
+}
+
+/* Helper function for handle_range_longs. If arg is int or long
+ object, returns it with incremented reference count. If arg is
+ float, raises type error. As a last resort, creates a new int by
+ calling arg type's nb_int method if it is defined. Returns NULL
+ and sets exception on error.
+
+ Returns a new reference to an int object. */
+static PyObject *
+get_range_long_argument(PyObject *arg, const char *name)
+{
+ PyObject *v;
+ PyNumberMethods *nb;
+ if (_PyAnyInt_Check(arg)) {
+ Py_INCREF(arg);
+ return arg;
+ }
+ if (PyFloat_Check(arg) ||
+ (nb = Py_TYPE(arg)->tp_as_number) == NULL ||
+ nb->nb_int == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "range() integer %s argument expected, got %s.",
+ name, arg->ob_type->tp_name);
+ return NULL;
+ }
+ v = nb->nb_int(arg);
+ if (v == NULL)
+ return NULL;
+ if (_PyAnyInt_Check(v))
+ return v;
+ Py_DECREF(v);
+ PyErr_SetString(PyExc_TypeError,
+ "__int__ should return int object");
+ return NULL;
+}
+
+/* An extension of builtin_range() that handles the case when PyLong
+ * arguments are given. */
+static PyObject *
+handle_range_longs(PyObject *self, PyObject *args)
+{
+ PyObject *ilow = NULL;
+ PyObject *ihigh = NULL;
+ PyObject *istep = NULL;
+
+ PyObject *low = NULL;
+ PyObject *high = NULL;
+ PyObject *step = NULL;
+
+ PyObject *curnum = NULL;
+ PyObject *v = NULL;
+ long bign;
+ Py_ssize_t i, n;
+ int cmp_result;
+
+ PyObject *zero = PyLong_FromLong(0);
+
+ if (zero == NULL)
+ return NULL;
+
+ if (!PyArg_UnpackTuple(args, "range", 1, 3, &ilow, &ihigh, &istep)) {
+ Py_DECREF(zero);
+ return NULL;
+ }
+
+ /* Figure out which way we were called, supply defaults, and be
+ * sure to incref everything so that the decrefs at the end
+ * are correct. NB: ilow, ihigh and istep are borrowed references.
+ */
+ assert(ilow != NULL);
+ if (ihigh == NULL) {
+ /* only 1 arg -- it's the upper limit */
+ ihigh = ilow;
+ ilow = NULL;
+ }
+
+ /* convert ihigh if necessary */
+ assert(ihigh != NULL);
+ high = get_range_long_argument(ihigh, "end");
+ if (high == NULL)
+ goto Fail;
+
+ /* ihigh correct now; do ilow */
+ if (ilow == NULL) {
+ Py_INCREF(zero);
+ low = zero;
+ }
+ else {
+ low = get_range_long_argument(ilow, "start");
+ if (low == NULL)
+ goto Fail;
+ }
+
+ /* ilow and ihigh correct now; do istep */
+ if (istep == NULL)
+ step = PyLong_FromLong(1);
+ else
+ step = get_range_long_argument(istep, "step");
+ if (step == NULL)
+ goto Fail;
+
+ if (PyObject_Cmp(step, zero, &cmp_result) == -1)
+ goto Fail;
+
+ if (cmp_result == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "range() step argument must not be zero");
+ goto Fail;
+ }
+
+ if (cmp_result > 0)
+ bign = get_len_of_range_longs(low, high, step);
+ else {
+ PyObject *neg_step = PyNumber_Negative(step);
+ if (neg_step == NULL)
+ goto Fail;
+ bign = get_len_of_range_longs(high, low, neg_step);
+ Py_DECREF(neg_step);
+ }
+
+ n = (Py_ssize_t)bign;
+ if (bign < 0 || (long)n != bign) {
+ PyErr_SetString(PyExc_OverflowError,
+ "range() result has too many items");
+ goto Fail;
+ }
+
+ v = PyList_New(n);
+ if (v == NULL)
+ goto Fail;
+
+ curnum = low;
+ Py_INCREF(curnum);
+
+ for (i = 0; i < n; i++) {
+ PyObject *w = PyNumber_Long(curnum);
+ PyObject *tmp_num;
+ if (w == NULL)
+ goto Fail;
+
+ PyList_SET_ITEM(v, i, w);
+
+ tmp_num = PyNumber_Add(curnum, step);
+ if (tmp_num == NULL)
+ goto Fail;
+
+ Py_DECREF(curnum);
+ curnum = tmp_num;
+ }
+ Py_DECREF(low);
+ Py_DECREF(high);
+ Py_DECREF(step);
+ Py_DECREF(zero);
+ Py_DECREF(curnum);
+ return v;
+
+ Fail:
+ Py_XDECREF(low);
+ Py_XDECREF(high);
+ Py_XDECREF(step);
+ Py_DECREF(zero);
+ Py_XDECREF(curnum);
+ Py_XDECREF(v);
+ return NULL;
+}
+
+/* Return number of items in range/xrange (lo, hi, step). step > 0
+ * required. Return a value < 0 if & only if the true value is too
+ * large to fit in a signed long.
+ */
+static long
+get_len_of_range(long lo, long hi, long step)
+{
+ /* -------------------------------------------------------------
+ If lo >= hi, the range is empty.
+ Else if n values are in the range, the last one is
+ lo + (n-1)*step, which must be <= hi-1. Rearranging,
+ n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
+ the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
+ the RHS is non-negative and so truncation is the same as the
+ floor. Letting M be the largest positive long, the worst case
+ for the RHS numerator is hi=M, lo=-M-1, and then
+ hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
+ precision to compute the RHS exactly.
+ ---------------------------------------------------------------*/
+ long n = 0;
+ if (lo < hi) {
+ unsigned long uhi = (unsigned long)hi;
+ unsigned long ulo = (unsigned long)lo;
+ unsigned long diff = uhi - ulo - 1;
+ n = (long)(diff / (unsigned long)step + 1);
+ }
+ return n;
+}
+
+static PyObject *
+builtin_range(PyObject *self, PyObject *args)
+{
+ long ilow = 0, ihigh = 0, istep = 1;
+ long bign;
+ Py_ssize_t i, n;
+
+ PyObject *v;
+
+ if (PyTuple_Size(args) <= 1) {
+ if (!PyArg_ParseTuple(args,
+ "l;range() requires 1-3 int arguments",
+ &ihigh)) {
+ PyErr_Clear();
+ return handle_range_longs(self, args);
+ }
+ }
+ else {
+ if (!PyArg_ParseTuple(args,
+ "ll|l;range() requires 1-3 int arguments",
+ &ilow, &ihigh, &istep)) {
+ PyErr_Clear();
+ return handle_range_longs(self, args);
+ }
+ }
+ if (istep == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "range() step argument must not be zero");
+ return NULL;
+ }
+ if (istep > 0)
+ bign = get_len_of_range(ilow, ihigh, istep);
+ else
+ bign = get_len_of_range(ihigh, ilow, -istep);
+ n = (Py_ssize_t)bign;
+ if (bign < 0 || (long)n != bign) {
+ PyErr_SetString(PyExc_OverflowError,
+ "range() result has too many items");
+ return NULL;
+ }
+ v = PyList_New(n);
+ if (v == NULL)
+ return NULL;
+ for (i = 0; i < n; i++) {
+ PyObject *w = PyInt_FromLong(ilow);
+ if (w == NULL) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ PyList_SET_ITEM(v, i, w);
+ ilow += istep;
+ }
+ return v;
+}
+
+PyDoc_STRVAR(range_doc,
+"range(stop) -> list of integers\n\
+range(start, stop[, step]) -> list of integers\n\
+\n\
+Return a list containing an arithmetic progression of integers.\n\
+range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.\n\
+When step is given, it specifies the increment (or decrement).\n\
+For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!\n\
+These are exactly the valid indices for a list of 4 elements.");
+
+
+static PyObject *
+builtin_raw_input(PyObject *self, PyObject *args)
+{
+ PyObject *v = NULL;
+ PyObject *fin = PySys_GetObject("stdin");
+ PyObject *fout = PySys_GetObject("stdout");
+
+ if (!PyArg_UnpackTuple(args, "[raw_]input", 0, 1, &v))
+ return NULL;
+
+ if (fin == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "[raw_]input: lost sys.stdin");
+ return NULL;
+ }
+ if (fout == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "[raw_]input: lost sys.stdout");
+ return NULL;
+ }
+ if (PyFile_SoftSpace(fout, 0)) {
+ if (PyFile_WriteString(" ", fout) != 0)
+ return NULL;
+ }
+ if (PyFile_AsFile(fin) && PyFile_AsFile(fout)
+ && isatty(fileno(PyFile_AsFile(fin)))
+ && isatty(fileno(PyFile_AsFile(fout)))) {
+ PyObject *po;
+ char *prompt;
+ char *s;
+ PyObject *result;
+ if (v != NULL) {
+ po = PyObject_Str(v);
+ if (po == NULL)
+ return NULL;
+ prompt = PyString_AsString(po);
+ if (prompt == NULL)
+ return NULL;
+ }
+ else {
+ po = NULL;
+ prompt = "";
+ }
+ s = PyOS_Readline(PyFile_AsFile(fin), PyFile_AsFile(fout),
+ prompt);
+ Py_XDECREF(po);
+ if (s == NULL) {
+ if (!PyErr_Occurred())
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ return NULL;
+ }
+ if (*s == '\0') {
+ PyErr_SetNone(PyExc_EOFError);
+ result = NULL;
+ }
+ else { /* strip trailing '\n' */
+ size_t len = strlen(s);
+ if (len > PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "[raw_]input: input too long");
+ result = NULL;
+ }
+ else {
+ result = PyString_FromStringAndSize(s, len-1);
+ }
+ }
+ PyMem_FREE(s);
+ return result;
+ }
+ if (v != NULL) {
+ if (PyFile_WriteObject(v, fout, Py_PRINT_RAW) != 0)
+ return NULL;
+ }
+ return PyFile_GetLine(fin, -1);
+}
+
+PyDoc_STRVAR(raw_input_doc,
+"raw_input([prompt]) -> string\n\
+\n\
+Read a string from standard input. The trailing newline is stripped.\n\
+If the user hits EOF (Unix: Ctl-D, Windows: Ctl-Z+Return), raise EOFError.\n\
+On Unix, GNU readline is used if enabled. The prompt string, if given,\n\
+is printed without a trailing newline before reading.");
+
+
+static PyObject *
+builtin_reduce(PyObject *self, PyObject *args)
+{
+ static PyObject *functools_reduce = NULL;
+
+ if (PyErr_WarnPy3k("reduce() not supported in 3.x; "
+ "use functools.reduce()", 1) < 0)
+ return NULL;
+
+ if (functools_reduce == NULL) {
+ PyObject *functools = PyImport_ImportModule("functools");
+ if (functools == NULL)
+ return NULL;
+ functools_reduce = PyObject_GetAttrString(functools, "reduce");
+ Py_DECREF(functools);
+ if (functools_reduce == NULL)
+ return NULL;
+ }
+ return PyObject_Call(functools_reduce, args, NULL);
+}
+
+PyDoc_STRVAR(reduce_doc,
+"reduce(function, sequence[, initial]) -> value\n\
+\n\
+Apply a function of two arguments cumulatively to the items of a sequence,\n\
+from left to right, so as to reduce the sequence to a single value.\n\
+For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
+((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
+of the sequence in the calculation, and serves as a default when the\n\
+sequence is empty.");
+
+
+static PyObject *
+builtin_reload(PyObject *self, PyObject *v)
+{
+ if (PyErr_WarnPy3k("In 3.x, reload() is renamed to imp.reload()",
+ 1) < 0)
+ return NULL;
+
+ return PyImport_ReloadModule(v);
+}
+
+PyDoc_STRVAR(reload_doc,
+"reload(module) -> module\n\
+\n\
+Reload the module. The module must have been successfully imported before.");
+
+
+static PyObject *
+builtin_repr(PyObject *self, PyObject *v)
+{
+ return PyObject_Repr(v);
+}
+
+PyDoc_STRVAR(repr_doc,
+"repr(object) -> string\n\
+\n\
+Return the canonical string representation of the object.\n\
+For most object types, eval(repr(object)) == object.");
+
+
+static PyObject *
+builtin_round(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ double x;
+ PyObject *o_ndigits = NULL;
+ Py_ssize_t ndigits;
+ static char *kwlist[] = {"number", "ndigits", 0};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|O:round",
+ kwlist, &x, &o_ndigits))
+ return NULL;
+
+ if (o_ndigits == NULL) {
+ /* second argument defaults to 0 */
+ ndigits = 0;
+ }
+ else {
+ /* interpret 2nd argument as a Py_ssize_t; clip on overflow */
+ ndigits = PyNumber_AsSsize_t(o_ndigits, NULL);
+ if (ndigits == -1 && PyErr_Occurred())
+ return NULL;
+ }
+
+ /* nans, infinities and zeros round to themselves */
+ if (!Py_IS_FINITE(x) || x == 0.0)
+ return PyFloat_FromDouble(x);
+
+ /* Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x
+ always rounds to itself. For ndigits < NDIGITS_MIN, x always
+ rounds to +-0.0. Here 0.30103 is an upper bound for log10(2). */
+#define NDIGITS_MAX ((int)((DBL_MANT_DIG-DBL_MIN_EXP) * 0.30103))
+#define NDIGITS_MIN (-(int)((DBL_MAX_EXP + 1) * 0.30103))
+ if (ndigits > NDIGITS_MAX)
+ /* return x */
+ return PyFloat_FromDouble(x);
+ else if (ndigits < NDIGITS_MIN)
+ /* return 0.0, but with sign of x */
+ return PyFloat_FromDouble(0.0*x);
+ else
+ /* finite x, and ndigits is not unreasonably large */
+ /* _Py_double_round is defined in floatobject.c */
+ return _Py_double_round(x, (int)ndigits);
+#undef NDIGITS_MAX
+#undef NDIGITS_MIN
+}
+
+PyDoc_STRVAR(round_doc,
+"round(number[, ndigits]) -> floating point number\n\
+\n\
+Round a number to a given precision in decimal digits (default 0 digits).\n\
+This always returns a floating point number. Precision may be negative.");
+
+static PyObject *
+builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *newlist, *v, *seq, *compare=NULL, *keyfunc=NULL, *newargs;
+ PyObject *callable;
+ static char *kwlist[] = {"iterable", "cmp", "key", "reverse", 0};
+ int reverse;
+
+ /* args 1-4 should match listsort in Objects/listobject.c */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOi:sorted",
+ kwlist, &seq, &compare, &keyfunc, &reverse))
+ return NULL;
+
+ newlist = PySequence_List(seq);
+ if (newlist == NULL)
+ return NULL;
+
+ callable = PyObject_GetAttrString(newlist, "sort");
+ if (callable == NULL) {
+ Py_DECREF(newlist);
+ return NULL;
+ }
+
+ newargs = PyTuple_GetSlice(args, 1, 4);
+ if (newargs == NULL) {
+ Py_DECREF(newlist);
+ Py_DECREF(callable);
+ return NULL;
+ }
+
+ v = PyObject_Call(callable, newargs, kwds);
+ Py_DECREF(newargs);
+ Py_DECREF(callable);
+ if (v == NULL) {
+ Py_DECREF(newlist);
+ return NULL;
+ }
+ Py_DECREF(v);
+ return newlist;
+}
+
+PyDoc_STRVAR(sorted_doc,
+"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list");
+
+static PyObject *
+builtin_vars(PyObject *self, PyObject *args)
+{
+ PyObject *v = NULL;
+ PyObject *d;
+
+ if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v))
+ return NULL;
+ if (v == NULL) {
+ d = PyEval_GetLocals();
+ if (d == NULL) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_SystemError,
+ "vars(): no locals!?");
+ }
+ else
+ Py_INCREF(d);
+ }
+ else {
+ d = PyObject_GetAttrString(v, "__dict__");
+ if (d == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "vars() argument must have __dict__ attribute");
+ return NULL;
+ }
+ }
+ return d;
+}
+
+PyDoc_STRVAR(vars_doc,
+"vars([object]) -> dictionary\n\
+\n\
+Without arguments, equivalent to locals().\n\
+With an argument, equivalent to object.__dict__.");
+
+
+static PyObject*
+builtin_sum(PyObject *self, PyObject *args)
+{
+ PyObject *seq;
+ PyObject *result = NULL;
+ PyObject *temp, *item, *iter;
+
+ if (!PyArg_UnpackTuple(args, "sum", 1, 2, &seq, &result))
+ return NULL;
+
+ iter = PyObject_GetIter(seq);
+ if (iter == NULL)
+ return NULL;
+
+ if (result == NULL) {
+ result = PyInt_FromLong(0);
+ if (result == NULL) {
+ Py_DECREF(iter);
+ return NULL;
+ }
+ } else {
+ /* reject string values for 'start' parameter */
+ if (PyObject_TypeCheck(result, &PyBaseString_Type)) {
+ PyErr_SetString(PyExc_TypeError,
+ "sum() can't sum strings [use ''.join(seq) instead]");
+ Py_DECREF(iter);
+ return NULL;
+ }
+ Py_INCREF(result);
+ }
+
+#ifndef SLOW_SUM
+ /* Fast addition by keeping temporary sums in C instead of new Python objects.
+ Assumes all inputs are the same type. If the assumption fails, default
+ to the more general routine.
+ */
+ if (PyInt_CheckExact(result)) {
+ long i_result = PyInt_AS_LONG(result);
+ Py_DECREF(result);
+ result = NULL;
+ while(result == NULL) {
+ item = PyIter_Next(iter);
+ if (item == NULL) {
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong(i_result);
+ }
+ if (PyInt_CheckExact(item)) {
+ long b = PyInt_AS_LONG(item);
+ long x = i_result + b;
+ if ((x^i_result) >= 0 || (x^b) >= 0) {
+ i_result = x;
+ Py_DECREF(item);
+ continue;
+ }
+ }
+ /* Either overflowed or is not an int. Restore real objects and process normally */
+ result = PyInt_FromLong(i_result);
+ if (result == NULL) {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+ return NULL;
+ }
+ temp = PyNumber_Add(result, item);
+ Py_DECREF(result);
+ Py_DECREF(item);
+ result = temp;
+ if (result == NULL) {
+ Py_DECREF(iter);
+ return NULL;
+ }
+ }
+ }
+
+ if (PyFloat_CheckExact(result)) {
+ double f_result = PyFloat_AS_DOUBLE(result);
+ Py_DECREF(result);
+ result = NULL;
+ while(result == NULL) {
+ item = PyIter_Next(iter);
+ if (item == NULL) {
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble(f_result);
+ }
+ if (PyFloat_CheckExact(item)) {
+ PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0)
+ f_result += PyFloat_AS_DOUBLE(item);
+ PyFPE_END_PROTECT(f_result)
+ Py_DECREF(item);
+ continue;
+ }
+ if (PyInt_CheckExact(item)) {
+ PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0)
+ f_result += (double)PyInt_AS_LONG(item);
+ PyFPE_END_PROTECT(f_result)
+ Py_DECREF(item);
+ continue;
+ }
+ result = PyFloat_FromDouble(f_result);
+ if (result == NULL) {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+ return NULL;
+ }
+ temp = PyNumber_Add(result, item);
+ Py_DECREF(result);
+ Py_DECREF(item);
+ result = temp;
+ if (result == NULL) {
+ Py_DECREF(iter);
+ return NULL;
+ }
+ }
+ }
+#endif
+
+ for(;;) {
+ item = PyIter_Next(iter);
+ if (item == NULL) {
+ /* error, or end-of-sequence */
+ if (PyErr_Occurred()) {
+ Py_DECREF(result);
+ result = NULL;
+ }
+ break;
+ }
+ /* It's tempting to use PyNumber_InPlaceAdd instead of
+ PyNumber_Add here, to avoid quadratic running time
+ when doing 'sum(list_of_lists, [])'. However, this
+ would produce a change in behaviour: a snippet like
+
+ empty = []
+ sum([[x] for x in range(10)], empty)
+
+ would change the value of empty. */
+ temp = PyNumber_Add(result, item);
+ Py_DECREF(result);
+ Py_DECREF(item);
+ result = temp;
+ if (result == NULL)
+ break;
+ }
+ Py_DECREF(iter);
+ return result;
+}
+
+PyDoc_STRVAR(sum_doc,
+"sum(iterable[, start]) -> value\n\
+\n\
+Return the sum of an iterable or sequence of numbers (NOT strings)\n\
+plus the value of 'start' (which defaults to 0). When the sequence is\n\
+empty, return start.");
+
+
+static PyObject *
+builtin_isinstance(PyObject *self, PyObject *args)
+{
+ PyObject *inst;
+ PyObject *cls;
+ int retval;
+
+ if (!PyArg_UnpackTuple(args, "isinstance", 2, 2, &inst, &cls))
+ return NULL;
+
+ retval = PyObject_IsInstance(inst, cls);
+ if (retval < 0)
+ return NULL;
+ return PyBool_FromLong(retval);
+}
+
+PyDoc_STRVAR(isinstance_doc,
+"isinstance(object, class-or-type-or-tuple) -> bool\n\
+\n\
+Return whether an object is an instance of a class or of a subclass thereof.\n\
+With a type as second argument, return whether that is the object's type.\n\
+The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for\n\
+isinstance(x, A) or isinstance(x, B) or ... (etc.).");
+
+
+static PyObject *
+builtin_issubclass(PyObject *self, PyObject *args)
+{
+ PyObject *derived;
+ PyObject *cls;
+ int retval;
+
+ if (!PyArg_UnpackTuple(args, "issubclass", 2, 2, &derived, &cls))
+ return NULL;
+
+ retval = PyObject_IsSubclass(derived, cls);
+ if (retval < 0)
+ return NULL;
+ return PyBool_FromLong(retval);
+}
+
+PyDoc_STRVAR(issubclass_doc,
+"issubclass(C, B) -> bool\n\
+\n\
+Return whether class C is a subclass (i.e., a derived class) of class B.\n\
+When using a tuple as the second argument issubclass(X, (A, B, ...)),\n\
+is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.).");
+
+
+static PyObject*
+builtin_zip(PyObject *self, PyObject *args)
+{
+ PyObject *ret;
+ const Py_ssize_t itemsize = PySequence_Length(args);
+ Py_ssize_t i;
+ PyObject *itlist; /* tuple of iterators */
+ Py_ssize_t len; /* guess at result length */
+
+ if (itemsize == 0)
+ return PyList_New(0);
+
+ /* args must be a tuple */
+ assert(PyTuple_Check(args));
+
+ /* Guess at result length: the shortest of the input lengths.
+ If some argument refuses to say, we refuse to guess too, lest
+ an argument like xrange(sys.maxint) lead us astray.*/
+ len = -1; /* unknown */
+ for (i = 0; i < itemsize; ++i) {
+ PyObject *item = PyTuple_GET_ITEM(args, i);
+ Py_ssize_t thislen = _PyObject_LengthHint(item, -2);
+ if (thislen < 0) {
+ if (thislen == -1)
+ return NULL;
+ len = -1;
+ break;
+ }
+ else if (len < 0 || thislen < len)
+ len = thislen;
+ }
+
+ /* allocate result list */
+ if (len < 0)
+ len = 10; /* arbitrary */
+ if ((ret = PyList_New(len)) == NULL)
+ return NULL;
+
+ /* obtain iterators */
+ itlist = PyTuple_New(itemsize);
+ if (itlist == NULL)
+ goto Fail_ret;
+ for (i = 0; i < itemsize; ++i) {
+ PyObject *item = PyTuple_GET_ITEM(args, i);
+ PyObject *it = PyObject_GetIter(item);
+ if (it == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Format(PyExc_TypeError,
+ "zip argument #%zd must support iteration",
+ i+1);
+ goto Fail_ret_itlist;
+ }
+ PyTuple_SET_ITEM(itlist, i, it);
+ }
+
+ /* build result into ret list */
+ for (i = 0; ; ++i) {
+ int j;
+ PyObject *next = PyTuple_New(itemsize);
+ if (!next)
+ goto Fail_ret_itlist;
+
+ for (j = 0; j < itemsize; j++) {
+ PyObject *it = PyTuple_GET_ITEM(itlist, j);
+ PyObject *item = PyIter_Next(it);
+ if (!item) {
+ if (PyErr_Occurred()) {
+ Py_DECREF(ret);
+ ret = NULL;
+ }
+ Py_DECREF(next);
+ Py_DECREF(itlist);
+ goto Done;
+ }
+ PyTuple_SET_ITEM(next, j, item);
+ }
+
+ if (i < len)
+ PyList_SET_ITEM(ret, i, next);
+ else {
+ int status = PyList_Append(ret, next);
+ Py_DECREF(next);
+ ++len;
+ if (status < 0)
+ goto Fail_ret_itlist;
+ }
+ }
+
+Done:
+ if (ret != NULL && i < len) {
+ /* The list is too big. */
+ if (PyList_SetSlice(ret, i, len, NULL) < 0)
+ return NULL;
+ }
+ return ret;
+
+Fail_ret_itlist:
+ Py_DECREF(itlist);
+Fail_ret:
+ Py_DECREF(ret);
+ return NULL;
+}
+
+
+PyDoc_STRVAR(zip_doc,
+"zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]\n\
+\n\
+Return a list of tuples, where each tuple contains the i-th element\n\
+from each of the argument sequences. The returned list is truncated\n\
+in length to the length of the shortest argument sequence.");
+
+
+static PyMethodDef builtin_methods[] = {
+ {"__import__", (PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc},
+ {"abs", builtin_abs, METH_O, abs_doc},
+ {"all", builtin_all, METH_O, all_doc},
+ {"any", builtin_any, METH_O, any_doc},
+ {"apply", builtin_apply, METH_VARARGS, apply_doc},
+ {"bin", builtin_bin, METH_O, bin_doc},
+ {"callable", builtin_callable, METH_O, callable_doc},
+ {"chr", builtin_chr, METH_VARARGS, chr_doc},
+ {"cmp", builtin_cmp, METH_VARARGS, cmp_doc},
+ {"coerce", builtin_coerce, METH_VARARGS, coerce_doc},
+ {"compile", (PyCFunction)builtin_compile, METH_VARARGS | METH_KEYWORDS, compile_doc},
+ {"delattr", builtin_delattr, METH_VARARGS, delattr_doc},
+ {"dir", builtin_dir, METH_VARARGS, dir_doc},
+ {"divmod", builtin_divmod, METH_VARARGS, divmod_doc},
+ {"eval", builtin_eval, METH_VARARGS, eval_doc},
+ {"execfile", builtin_execfile, METH_VARARGS, execfile_doc},
+ {"filter", builtin_filter, METH_VARARGS, filter_doc},
+ {"format", builtin_format, METH_VARARGS, format_doc},
+ {"getattr", builtin_getattr, METH_VARARGS, getattr_doc},
+ {"globals", (PyCFunction)builtin_globals, METH_NOARGS, globals_doc},
+ {"hasattr", builtin_hasattr, METH_VARARGS, hasattr_doc},
+ {"hash", builtin_hash, METH_O, hash_doc},
+ {"hex", builtin_hex, METH_O, hex_doc},
+ {"id", builtin_id, METH_O, id_doc},
+ {"input", builtin_input, METH_VARARGS, input_doc},
+ {"intern", builtin_intern, METH_VARARGS, intern_doc},
+ {"isinstance", builtin_isinstance, METH_VARARGS, isinstance_doc},
+ {"issubclass", builtin_issubclass, METH_VARARGS, issubclass_doc},
+ {"iter", builtin_iter, METH_VARARGS, iter_doc},
+ {"len", builtin_len, METH_O, len_doc},
+ {"locals", (PyCFunction)builtin_locals, METH_NOARGS, locals_doc},
+ {"map", builtin_map, METH_VARARGS, map_doc},
+ {"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
+ {"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
+ {"next", builtin_next, METH_VARARGS, next_doc},
+ {"oct", builtin_oct, METH_O, oct_doc},
+ {"open", (PyCFunction)builtin_open, METH_VARARGS | METH_KEYWORDS, open_doc},
+ {"ord", builtin_ord, METH_O, ord_doc},
+ {"pow", builtin_pow, METH_VARARGS, pow_doc},
+ {"print", (PyCFunction)builtin_print, METH_VARARGS | METH_KEYWORDS, print_doc},
+ {"range", builtin_range, METH_VARARGS, range_doc},
+ {"raw_input", builtin_raw_input, METH_VARARGS, raw_input_doc},
+ {"reduce", builtin_reduce, METH_VARARGS, reduce_doc},
+ {"reload", builtin_reload, METH_O, reload_doc},
+ {"repr", builtin_repr, METH_O, repr_doc},
+ {"round", (PyCFunction)builtin_round, METH_VARARGS | METH_KEYWORDS, round_doc},
+ {"setattr", builtin_setattr, METH_VARARGS, setattr_doc},
+ {"sorted", (PyCFunction)builtin_sorted, METH_VARARGS | METH_KEYWORDS, sorted_doc},
+ {"sum", builtin_sum, METH_VARARGS, sum_doc},
+#ifdef Py_USING_UNICODE
+ {"unichr", builtin_unichr, METH_VARARGS, unichr_doc},
+#endif
+ {"vars", builtin_vars, METH_VARARGS, vars_doc},
+ {"zip", builtin_zip, METH_VARARGS, zip_doc},
+ {NULL, NULL},
+};
+
+PyDoc_STRVAR(builtin_doc,
+"Built-in functions, exceptions, and other objects.\n\
+\n\
+Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices.");
+
+PyObject *
+_PyBuiltin_Init(void)
+{
+ PyObject *mod, *dict, *debug;
+ mod = Py_InitModule4("__builtin__", builtin_methods,
+ builtin_doc, (PyObject *)NULL,
+ PYTHON_API_VERSION);
+ if (mod == NULL)
+ return NULL;
+ dict = PyModule_GetDict(mod);
+
+#ifdef Py_TRACE_REFS
+ /* __builtin__ exposes a number of statically allocated objects
+ * that, before this code was added in 2.3, never showed up in
+ * the list of "all objects" maintained by Py_TRACE_REFS. As a
+ * result, programs leaking references to None and False (etc)
+ * couldn't be diagnosed by examining sys.getobjects(0).
+ */
+#define ADD_TO_ALL(OBJECT) _Py_AddToAllObjects((PyObject *)(OBJECT), 0)
+#else
+#define ADD_TO_ALL(OBJECT) (void)0
+#endif
+
+#define SETBUILTIN(NAME, OBJECT) \
+ if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0) \
+ return NULL; \
+ ADD_TO_ALL(OBJECT)
+
+ SETBUILTIN("None", Py_None);
+ SETBUILTIN("Ellipsis", Py_Ellipsis);
+ SETBUILTIN("NotImplemented", Py_NotImplemented);
+ SETBUILTIN("False", Py_False);
+ SETBUILTIN("True", Py_True);
+ SETBUILTIN("basestring", &PyBaseString_Type);
+ SETBUILTIN("bool", &PyBool_Type);
+ SETBUILTIN("memoryview", &PyMemoryView_Type);
+ SETBUILTIN("bytearray", &PyByteArray_Type);
+ SETBUILTIN("bytes", &PyString_Type);
+ SETBUILTIN("buffer", &PyBuffer_Type);
+ SETBUILTIN("classmethod", &PyClassMethod_Type);
+#ifndef WITHOUT_COMPLEX
+ SETBUILTIN("complex", &PyComplex_Type);
+#endif
+ SETBUILTIN("dict", &PyDict_Type);
+ SETBUILTIN("enumerate", &PyEnum_Type);
+ SETBUILTIN("file", &PyFile_Type);
+ SETBUILTIN("float", &PyFloat_Type);
+ SETBUILTIN("frozenset", &PyFrozenSet_Type);
+ SETBUILTIN("property", &PyProperty_Type);
+ SETBUILTIN("int", &PyInt_Type);
+ SETBUILTIN("list", &PyList_Type);
+ SETBUILTIN("long", &PyLong_Type);
+ SETBUILTIN("object", &PyBaseObject_Type);
+ SETBUILTIN("reversed", &PyReversed_Type);
+ SETBUILTIN("set", &PySet_Type);
+ SETBUILTIN("slice", &PySlice_Type);
+ SETBUILTIN("staticmethod", &PyStaticMethod_Type);
+ SETBUILTIN("str", &PyString_Type);
+ SETBUILTIN("super", &PySuper_Type);
+ SETBUILTIN("tuple", &PyTuple_Type);
+ SETBUILTIN("type", &PyType_Type);
+ SETBUILTIN("xrange", &PyRange_Type);
+#ifdef Py_USING_UNICODE
+ SETBUILTIN("unicode", &PyUnicode_Type);
+#endif
+ debug = PyBool_FromLong(Py_OptimizeFlag == 0);
+ if (PyDict_SetItemString(dict, "__debug__", debug) < 0) {
+ Py_XDECREF(debug);
+ return NULL;
+ }
+ Py_XDECREF(debug);
+
+ return mod;
+#undef ADD_TO_ALL
+#undef SETBUILTIN
+}
+
+/* Helper for filter(): filter a tuple through a function */
+
+static PyObject *
+filtertuple(PyObject *func, PyObject *tuple)
+{
+ PyObject *result;
+ Py_ssize_t i, j;
+ Py_ssize_t len = PyTuple_Size(tuple);
+
+ if (len == 0) {
+ if (PyTuple_CheckExact(tuple))
+ Py_INCREF(tuple);
+ else
+ tuple = PyTuple_New(0);
+ return tuple;
+ }
+
+ if ((result = PyTuple_New(len)) == NULL)
+ return NULL;
+
+ for (i = j = 0; i < len; ++i) {
+ PyObject *item, *good;
+ int ok;
+
+ if (tuple->ob_type->tp_as_sequence &&
+ tuple->ob_type->tp_as_sequence->sq_item) {
+ item = tuple->ob_type->tp_as_sequence->sq_item(tuple, i);
+ if (item == NULL)
+ goto Fail_1;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "filter(): unsubscriptable tuple");
+ goto Fail_1;
+ }
+ if (func == Py_None) {
+ Py_INCREF(item);
+ good = item;
+ }
+ else {
+ PyObject *arg = PyTuple_Pack(1, item);
+ if (arg == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ good = PyEval_CallObject(func, arg);
+ Py_DECREF(arg);
+ if (good == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ }
+ ok = PyObject_IsTrue(good);
+ Py_DECREF(good);
+ if (ok > 0) {
+ if (PyTuple_SetItem(result, j++, item) < 0)
+ goto Fail_1;
+ }
+ else {
+ Py_DECREF(item);
+ if (ok < 0)
+ goto Fail_1;
+ }
+ }
+
+ if (_PyTuple_Resize(&result, j) < 0)
+ return NULL;
+
+ return result;
+
+Fail_1:
+ Py_DECREF(result);
+ return NULL;
+}
+
+
+/* Helper for filter(): filter a string through a function */
+
+static PyObject *
+filterstring(PyObject *func, PyObject *strobj)
+{
+ PyObject *result;
+ Py_ssize_t i, j;
+ Py_ssize_t len = PyString_Size(strobj);
+ Py_ssize_t outlen = len;
+
+ if (func == Py_None) {
+ /* If it's a real string we can return the original,
+ * as no character is ever false and __getitem__
+ * does return this character. If it's a subclass
+ * we must go through the __getitem__ loop */
+ if (PyString_CheckExact(strobj)) {
+ Py_INCREF(strobj);
+ return strobj;
+ }
+ }
+ if ((result = PyString_FromStringAndSize(NULL, len)) == NULL)
+ return NULL;
+
+ for (i = j = 0; i < len; ++i) {
+ PyObject *item;
+ int ok;
+
+ item = (*strobj->ob_type->tp_as_sequence->sq_item)(strobj, i);
+ if (item == NULL)
+ goto Fail_1;
+ if (func==Py_None) {
+ ok = 1;
+ } else {
+ PyObject *arg, *good;
+ arg = PyTuple_Pack(1, item);
+ if (arg == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ good = PyEval_CallObject(func, arg);
+ Py_DECREF(arg);
+ if (good == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ ok = PyObject_IsTrue(good);
+ Py_DECREF(good);
+ }
+ if (ok > 0) {
+ Py_ssize_t reslen;
+ if (!PyString_Check(item)) {
+ PyErr_SetString(PyExc_TypeError, "can't filter str to str:"
+ " __getitem__ returned different type");
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ reslen = PyString_GET_SIZE(item);
+ if (reslen == 1) {
+ PyString_AS_STRING(result)[j++] =
+ PyString_AS_STRING(item)[0];
+ } else {
+ /* do we need more space? */
+ Py_ssize_t need = j;
+
+ /* calculate space requirements while checking for overflow */
+ if (need > PY_SSIZE_T_MAX - reslen) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+
+ need += reslen;
+
+ if (need > PY_SSIZE_T_MAX - len) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+
+ need += len;
+
+ if (need <= i) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+
+ need = need - i - 1;
+
+ assert(need >= 0);
+ assert(outlen >= 0);
+
+ if (need > outlen) {
+ /* overallocate, to avoid reallocations */
+ if (outlen > PY_SSIZE_T_MAX / 2) {
+ Py_DECREF(item);
+ return NULL;
+ }
+
+ if (need<2*outlen) {
+ need = 2*outlen;
+ }
+ if (_PyString_Resize(&result, need)) {
+ Py_DECREF(item);
+ return NULL;
+ }
+ outlen = need;
+ }
+ memcpy(
+ PyString_AS_STRING(result) + j,
+ PyString_AS_STRING(item),
+ reslen
+ );
+ j += reslen;
+ }
+ }
+ Py_DECREF(item);
+ if (ok < 0)
+ goto Fail_1;
+ }
+
+ if (j < outlen)
+ _PyString_Resize(&result, j);
+
+ return result;
+
+Fail_1:
+ Py_DECREF(result);
+ return NULL;
+}
+
+#ifdef Py_USING_UNICODE
+/* Helper for filter(): filter a Unicode object through a function */
+
+static PyObject *
+filterunicode(PyObject *func, PyObject *strobj)
+{
+ PyObject *result;
+ register Py_ssize_t i, j;
+ Py_ssize_t len = PyUnicode_GetSize(strobj);
+ Py_ssize_t outlen = len;
+
+ if (func == Py_None) {
+ /* If it's a real string we can return the original,
+ * as no character is ever false and __getitem__
+ * does return this character. If it's a subclass
+ * we must go through the __getitem__ loop */
+ if (PyUnicode_CheckExact(strobj)) {
+ Py_INCREF(strobj);
+ return strobj;
+ }
+ }
+ if ((result = PyUnicode_FromUnicode(NULL, len)) == NULL)
+ return NULL;
+
+ for (i = j = 0; i < len; ++i) {
+ PyObject *item, *arg, *good;
+ int ok;
+
+ item = (*strobj->ob_type->tp_as_sequence->sq_item)(strobj, i);
+ if (item == NULL)
+ goto Fail_1;
+ if (func == Py_None) {
+ ok = 1;
+ } else {
+ arg = PyTuple_Pack(1, item);
+ if (arg == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ good = PyEval_CallObject(func, arg);
+ Py_DECREF(arg);
+ if (good == NULL) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ ok = PyObject_IsTrue(good);
+ Py_DECREF(good);
+ }
+ if (ok > 0) {
+ Py_ssize_t reslen;
+ if (!PyUnicode_Check(item)) {
+ PyErr_SetString(PyExc_TypeError,
+ "can't filter unicode to unicode:"
+ " __getitem__ returned different type");
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ reslen = PyUnicode_GET_SIZE(item);
+ if (reslen == 1)
+ PyUnicode_AS_UNICODE(result)[j++] =
+ PyUnicode_AS_UNICODE(item)[0];
+ else {
+ /* do we need more space? */
+ Py_ssize_t need = j + reslen + len - i - 1;
+
+ /* check that didnt overflow */
+ if ((j > PY_SSIZE_T_MAX - reslen) ||
+ ((j + reslen) > PY_SSIZE_T_MAX - len) ||
+ ((j + reslen + len) < i) ||
+ ((j + reslen + len - i) <= 0)) {
+ Py_DECREF(item);
+ return NULL;
+ }
+
+ assert(need >= 0);
+ assert(outlen >= 0);
+
+ if (need > outlen) {
+ /* overallocate, to avoid reallocations */
+ if (need < 2 * outlen) {
+ if (outlen > PY_SSIZE_T_MAX / 2) {
+ Py_DECREF(item);
+ return NULL;
+ } else {
+ need = 2 * outlen;
+ }
+ }
+
+ if (PyUnicode_Resize(&result, need) < 0) {
+ Py_DECREF(item);
+ goto Fail_1;
+ }
+ outlen = need;
+ }
+ memcpy(PyUnicode_AS_UNICODE(result) + j,
+ PyUnicode_AS_UNICODE(item),
+ reslen*sizeof(Py_UNICODE));
+ j += reslen;
+ }
+ }
+ Py_DECREF(item);
+ if (ok < 0)
+ goto Fail_1;
+ }
+
+ if (j < outlen)
+ PyUnicode_Resize(&result, j);
+
+ return result;
+
+Fail_1:
+ Py_DECREF(result);
+ return NULL;
+}
+#endif
diff --git a/contrib/tools/python/src/Python/ceval.c b/contrib/tools/python/src/Python/ceval.c
new file mode 100644
index 0000000000..e1140a8e40
--- /dev/null
+++ b/contrib/tools/python/src/Python/ceval.c
@@ -0,0 +1,5278 @@
+
+/* Execute compiled code */
+
+/* XXX TO DO:
+ XXX speed up searching for keywords by using a dictionary
+ XXX document it!
+ */
+
+/* enable more aggressive intra-module optimizations, where available */
+#define PY_LOCAL_AGGRESSIVE
+
+#include "Python.h"
+
+#include "code.h"
+#include "frameobject.h"
+#include "eval.h"
+#include "opcode.h"
+#include "structmember.h"
+
+#include <ctype.h>
+
+#ifndef WITH_TSC
+
+#define READ_TIMESTAMP(var)
+
+#else
+
+typedef unsigned long long uint64;
+
+/* PowerPC support.
+ "__ppc__" appears to be the preprocessor definition to detect on OS X, whereas
+ "__powerpc__" appears to be the correct one for Linux with GCC
+*/
+#if defined(__ppc__) || defined (__powerpc__)
+
+#define READ_TIMESTAMP(var) ppc_getcounter(&var)
+
+static void
+ppc_getcounter(uint64 *v)
+{
+ register unsigned long tbu, tb, tbu2;
+
+ loop:
+ asm volatile ("mftbu %0" : "=r" (tbu) );
+ asm volatile ("mftb %0" : "=r" (tb) );
+ asm volatile ("mftbu %0" : "=r" (tbu2));
+ if (__builtin_expect(tbu != tbu2, 0)) goto loop;
+
+ /* The slightly peculiar way of writing the next lines is
+ compiled better by GCC than any other way I tried. */
+ ((long*)(v))[0] = tbu;
+ ((long*)(v))[1] = tb;
+}
+
+#elif defined(__i386__)
+
+/* this is for linux/x86 (and probably any other GCC/x86 combo) */
+
+#define READ_TIMESTAMP(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+
+#elif defined(__x86_64__)
+
+/* for gcc/x86_64, the "A" constraint in DI mode means *either* rax *or* rdx;
+ not edx:eax as it does for i386. Since rdtsc puts its result in edx:eax
+ even in 64-bit mode, we need to use "a" and "d" for the lower and upper
+ 32-bit pieces of the result. */
+
+#define READ_TIMESTAMP(val) do { \
+ unsigned int h, l; \
+ __asm__ __volatile__("rdtsc" : "=a" (l), "=d" (h)); \
+ (val) = ((uint64)l) | (((uint64)h) << 32); \
+ } while(0)
+
+
+#else
+
+#error "Don't know how to implement timestamp counter for this architecture"
+
+#endif
+
+void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1,
+ uint64 loop0, uint64 loop1, uint64 intr0, uint64 intr1)
+{
+ uint64 intr, inst, loop;
+ PyThreadState *tstate = PyThreadState_Get();
+ if (!tstate->interp->tscdump)
+ return;
+ intr = intr1 - intr0;
+ inst = inst1 - inst0 - intr;
+ loop = loop1 - loop0 - intr;
+ fprintf(stderr, "opcode=%03d t=%d inst=%06lld loop=%06lld\n",
+ opcode, ticked, inst, loop);
+}
+
+#endif
+
+/* Turn this on if your compiler chokes on the big switch: */
+/* #define CASE_TOO_BIG 1 */
+
+#ifdef Py_DEBUG
+/* For debugging the interpreter: */
+#define LLTRACE 1 /* Low-level trace feature */
+#define CHECKEXC 1 /* Double-check exception checking */
+#endif
+
+typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
+
+/* Forward declarations */
+#ifdef WITH_TSC
+static PyObject * call_function(PyObject ***, int, uint64*, uint64*);
+#else
+static PyObject * call_function(PyObject ***, int);
+#endif
+static PyObject * fast_function(PyObject *, PyObject ***, int, int, int);
+static PyObject * do_call(PyObject *, PyObject ***, int, int);
+static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int);
+static PyObject * update_keyword_args(PyObject *, int, PyObject ***,
+ PyObject *);
+static PyObject * update_star_args(int, int, PyObject *, PyObject ***);
+static PyObject * load_args(PyObject ***, int);
+#define CALL_FLAG_VAR 1
+#define CALL_FLAG_KW 2
+
+#ifdef LLTRACE
+static int lltrace;
+static int prtrace(PyObject *, char *);
+#endif
+static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *,
+ int, PyObject *);
+static int call_trace_protected(Py_tracefunc, PyObject *,
+ PyFrameObject *, int, PyObject *);
+static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *);
+static int maybe_call_line_trace(Py_tracefunc, PyObject *,
+ PyFrameObject *, int *, int *, int *);
+
+static PyObject * apply_slice(PyObject *, PyObject *, PyObject *);
+static int assign_slice(PyObject *, PyObject *,
+ PyObject *, PyObject *);
+static PyObject * cmp_outcome(int, PyObject *, PyObject *);
+static PyObject * import_from(PyObject *, PyObject *);
+static int import_all_from(PyObject *, PyObject *);
+static PyObject * build_class(PyObject *, PyObject *, PyObject *);
+static int exec_statement(PyFrameObject *,
+ PyObject *, PyObject *, PyObject *);
+static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *);
+static void reset_exc_info(PyThreadState *);
+static void format_exc_check_arg(PyObject *, char *, PyObject *);
+static PyObject * string_concatenate(PyObject *, PyObject *,
+ PyFrameObject *, unsigned char *);
+static PyObject * kwd_as_string(PyObject *);
+static PyObject * special_lookup(PyObject *, char *, PyObject **);
+
+#define NAME_ERROR_MSG \
+ "name '%.200s' is not defined"
+#define GLOBAL_NAME_ERROR_MSG \
+ "global name '%.200s' is not defined"
+#define UNBOUNDLOCAL_ERROR_MSG \
+ "local variable '%.200s' referenced before assignment"
+#define UNBOUNDFREE_ERROR_MSG \
+ "free variable '%.200s' referenced before assignment" \
+ " in enclosing scope"
+
+/* Dynamic execution profile */
+#ifdef DYNAMIC_EXECUTION_PROFILE
+#ifdef DXPAIRS
+static long dxpairs[257][256];
+#define dxp dxpairs[256]
+#else
+static long dxp[256];
+#endif
+#endif
+
+/* Function call profile */
+#ifdef CALL_PROFILE
+#define PCALL_NUM 11
+static int pcall[PCALL_NUM];
+
+#define PCALL_ALL 0
+#define PCALL_FUNCTION 1
+#define PCALL_FAST_FUNCTION 2
+#define PCALL_FASTER_FUNCTION 3
+#define PCALL_METHOD 4
+#define PCALL_BOUND_METHOD 5
+#define PCALL_CFUNCTION 6
+#define PCALL_TYPE 7
+#define PCALL_GENERATOR 8
+#define PCALL_OTHER 9
+#define PCALL_POP 10
+
+/* Notes about the statistics
+
+ PCALL_FAST stats
+
+ FAST_FUNCTION means no argument tuple needs to be created.
+ FASTER_FUNCTION means that the fast-path frame setup code is used.
+
+ If there is a method call where the call can be optimized by changing
+ the argument tuple and calling the function directly, it gets recorded
+ twice.
+
+ As a result, the relationship among the statistics appears to be
+ PCALL_ALL == PCALL_FUNCTION + PCALL_METHOD - PCALL_BOUND_METHOD +
+ PCALL_CFUNCTION + PCALL_TYPE + PCALL_GENERATOR + PCALL_OTHER
+ PCALL_FUNCTION > PCALL_FAST_FUNCTION > PCALL_FASTER_FUNCTION
+ PCALL_METHOD > PCALL_BOUND_METHOD
+*/
+
+#define PCALL(POS) pcall[POS]++
+
+PyObject *
+PyEval_GetCallStats(PyObject *self)
+{
+ return Py_BuildValue("iiiiiiiiiii",
+ pcall[0], pcall[1], pcall[2], pcall[3],
+ pcall[4], pcall[5], pcall[6], pcall[7],
+ pcall[8], pcall[9], pcall[10]);
+}
+#else
+#define PCALL(O)
+
+PyObject *
+PyEval_GetCallStats(PyObject *self)
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+
+#ifdef WITH_THREAD
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "pythread.h"
+
+static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */
+static PyThread_type_lock pending_lock = 0; /* for pending calls */
+static long main_thread = 0;
+
+int
+PyEval_ThreadsInitialized(void)
+{
+ return interpreter_lock != 0;
+}
+
+void
+PyEval_InitThreads(void)
+{
+ if (interpreter_lock)
+ return;
+ interpreter_lock = PyThread_allocate_lock();
+ PyThread_acquire_lock(interpreter_lock, 1);
+ main_thread = PyThread_get_thread_ident();
+}
+
+void
+PyEval_AcquireLock(void)
+{
+ PyThread_acquire_lock(interpreter_lock, 1);
+}
+
+void
+PyEval_ReleaseLock(void)
+{
+ PyThread_release_lock(interpreter_lock);
+}
+
+void
+PyEval_AcquireThread(PyThreadState *tstate)
+{
+ if (tstate == NULL)
+ Py_FatalError("PyEval_AcquireThread: NULL new thread state");
+ /* Check someone has called PyEval_InitThreads() to create the lock */
+ assert(interpreter_lock);
+ PyThread_acquire_lock(interpreter_lock, 1);
+ if (PyThreadState_Swap(tstate) != NULL)
+ Py_FatalError(
+ "PyEval_AcquireThread: non-NULL old thread state");
+}
+
+void
+PyEval_ReleaseThread(PyThreadState *tstate)
+{
+ if (tstate == NULL)
+ Py_FatalError("PyEval_ReleaseThread: NULL thread state");
+ if (PyThreadState_Swap(NULL) != tstate)
+ Py_FatalError("PyEval_ReleaseThread: wrong thread state");
+ PyThread_release_lock(interpreter_lock);
+}
+
+/* This function is called from PyOS_AfterFork to ensure that newly
+ created child processes don't hold locks referring to threads which
+ are not running in the child process. (This could also be done using
+ pthread_atfork mechanism, at least for the pthreads implementation.) */
+
+void
+PyEval_ReInitThreads(void)
+{
+ PyObject *threading, *result;
+ PyThreadState *tstate;
+
+ if (!interpreter_lock)
+ return;
+ /*XXX Can't use PyThread_free_lock here because it does too
+ much error-checking. Doing this cleanly would require
+ adding a new function to each thread_*.h. Instead, just
+ create a new lock and waste a little bit of memory */
+ interpreter_lock = PyThread_allocate_lock();
+ pending_lock = PyThread_allocate_lock();
+ PyThread_acquire_lock(interpreter_lock, 1);
+ main_thread = PyThread_get_thread_ident();
+
+ /* Update the threading module with the new state.
+ */
+ tstate = PyThreadState_GET();
+ threading = PyMapping_GetItemString(tstate->interp->modules,
+ "threading");
+ if (threading == NULL) {
+ /* threading not imported */
+ PyErr_Clear();
+ return;
+ }
+ result = PyObject_CallMethod(threading, "_after_fork", NULL);
+ if (result == NULL)
+ PyErr_WriteUnraisable(threading);
+ else
+ Py_DECREF(result);
+ Py_DECREF(threading);
+}
+#endif
+
+/* Functions save_thread and restore_thread are always defined so
+ dynamically loaded modules needn't be compiled separately for use
+ with and without threads: */
+
+PyThreadState *
+PyEval_SaveThread(void)
+{
+ PyThreadState *tstate = PyThreadState_Swap(NULL);
+ if (tstate == NULL)
+ Py_FatalError("PyEval_SaveThread: NULL tstate");
+#ifdef WITH_THREAD
+ if (interpreter_lock)
+ PyThread_release_lock(interpreter_lock);
+#endif
+ return tstate;
+}
+
+void
+PyEval_RestoreThread(PyThreadState *tstate)
+{
+ if (tstate == NULL)
+ Py_FatalError("PyEval_RestoreThread: NULL tstate");
+#ifdef WITH_THREAD
+ if (interpreter_lock) {
+ int err = errno;
+ PyThread_acquire_lock(interpreter_lock, 1);
+ errno = err;
+ }
+#endif
+ PyThreadState_Swap(tstate);
+}
+
+
+/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
+ signal handlers or Mac I/O completion routines) can schedule calls
+ to a function to be called synchronously.
+ The synchronous function is called with one void* argument.
+ It should return 0 for success or -1 for failure -- failure should
+ be accompanied by an exception.
+
+ If registry succeeds, the registry function returns 0; if it fails
+ (e.g. due to too many pending calls) it returns -1 (without setting
+ an exception condition).
+
+ Note that because registry may occur from within signal handlers,
+ or other asynchronous events, calling malloc() is unsafe!
+
+#ifdef WITH_THREAD
+ Any thread can schedule pending calls, but only the main thread
+ will execute them.
+ There is no facility to schedule calls to a particular thread, but
+ that should be easy to change, should that ever be required. In
+ that case, the static variables here should go into the python
+ threadstate.
+#endif
+*/
+
+#ifdef WITH_THREAD
+
+/* The WITH_THREAD implementation is thread-safe. It allows
+ scheduling to be made from any thread, and even from an executing
+ callback.
+ */
+
+#define NPENDINGCALLS 32
+static struct {
+ int (*func)(void *);
+ void *arg;
+} pendingcalls[NPENDINGCALLS];
+static int pendingfirst = 0;
+static int pendinglast = 0;
+static volatile int pendingcalls_to_do = 1; /* trigger initialization of lock */
+static char pendingbusy = 0;
+
+int
+Py_AddPendingCall(int (*func)(void *), void *arg)
+{
+ int i, j, result=0;
+ PyThread_type_lock lock = pending_lock;
+
+ /* try a few times for the lock. Since this mechanism is used
+ * for signal handling (on the main thread), there is a (slim)
+ * chance that a signal is delivered on the same thread while we
+ * hold the lock during the Py_MakePendingCalls() function.
+ * This avoids a deadlock in that case.
+ * Note that signals can be delivered on any thread. In particular,
+ * on Windows, a SIGINT is delivered on a system-created worker
+ * thread.
+ * We also check for lock being NULL, in the unlikely case that
+ * this function is called before any bytecode evaluation takes place.
+ */
+ if (lock != NULL) {
+ for (i = 0; i<100; i++) {
+ if (PyThread_acquire_lock(lock, NOWAIT_LOCK))
+ break;
+ }
+ if (i == 100)
+ return -1;
+ }
+
+ i = pendinglast;
+ j = (i + 1) % NPENDINGCALLS;
+ if (j == pendingfirst) {
+ result = -1; /* Queue full */
+ } else {
+ pendingcalls[i].func = func;
+ pendingcalls[i].arg = arg;
+ pendinglast = j;
+ }
+ /* signal main loop */
+ _Py_Ticker = 0;
+ pendingcalls_to_do = 1;
+ if (lock != NULL)
+ PyThread_release_lock(lock);
+ return result;
+}
+
+int
+Py_MakePendingCalls(void)
+{
+ int i;
+ int r = 0;
+
+ if (!pending_lock) {
+ /* initial allocation of the lock */
+ pending_lock = PyThread_allocate_lock();
+ if (pending_lock == NULL)
+ return -1;
+ }
+
+ /* only service pending calls on main thread */
+ if (main_thread && PyThread_get_thread_ident() != main_thread)
+ return 0;
+ /* don't perform recursive pending calls */
+ if (pendingbusy)
+ return 0;
+ pendingbusy = 1;
+ /* perform a bounded number of calls, in case of recursion */
+ for (i=0; i<NPENDINGCALLS; i++) {
+ int j;
+ int (*func)(void *);
+ void *arg = NULL;
+
+ /* pop one item off the queue while holding the lock */
+ PyThread_acquire_lock(pending_lock, WAIT_LOCK);
+ j = pendingfirst;
+ if (j == pendinglast) {
+ func = NULL; /* Queue empty */
+ } else {
+ func = pendingcalls[j].func;
+ arg = pendingcalls[j].arg;
+ pendingfirst = (j + 1) % NPENDINGCALLS;
+ }
+ pendingcalls_to_do = pendingfirst != pendinglast;
+ PyThread_release_lock(pending_lock);
+ /* having released the lock, perform the callback */
+ if (func == NULL)
+ break;
+ r = func(arg);
+ if (r)
+ break;
+ }
+ pendingbusy = 0;
+ return r;
+}
+
+#else /* if ! defined WITH_THREAD */
+
+/*
+ WARNING! ASYNCHRONOUSLY EXECUTING CODE!
+ This code is used for signal handling in python that isn't built
+ with WITH_THREAD.
+ Don't use this implementation when Py_AddPendingCalls() can happen
+ on a different thread!
+
+ There are two possible race conditions:
+ (1) nested asynchronous calls to Py_AddPendingCall()
+ (2) AddPendingCall() calls made while pending calls are being processed.
+
+ (1) is very unlikely because typically signal delivery
+ is blocked during signal handling. So it should be impossible.
+ (2) is a real possibility.
+ The current code is safe against (2), but not against (1).
+ The safety against (2) is derived from the fact that only one
+ thread is present, interrupted by signals, and that the critical
+ section is protected with the "busy" variable. On Windows, which
+ delivers SIGINT on a system thread, this does not hold and therefore
+ Windows really shouldn't use this version.
+ The two threads could theoretically wiggle around the "busy" variable.
+*/
+
+#define NPENDINGCALLS 32
+static struct {
+ int (*func)(void *);
+ void *arg;
+} pendingcalls[NPENDINGCALLS];
+static volatile int pendingfirst = 0;
+static volatile int pendinglast = 0;
+static volatile int pendingcalls_to_do = 0;
+
+int
+Py_AddPendingCall(int (*func)(void *), void *arg)
+{
+ static volatile int busy = 0;
+ int i, j;
+ /* XXX Begin critical section */
+ if (busy)
+ return -1;
+ busy = 1;
+ i = pendinglast;
+ j = (i + 1) % NPENDINGCALLS;
+ if (j == pendingfirst) {
+ busy = 0;
+ return -1; /* Queue full */
+ }
+ pendingcalls[i].func = func;
+ pendingcalls[i].arg = arg;
+ pendinglast = j;
+
+ _Py_Ticker = 0;
+ pendingcalls_to_do = 1; /* Signal main loop */
+ busy = 0;
+ /* XXX End critical section */
+ return 0;
+}
+
+int
+Py_MakePendingCalls(void)
+{
+ static int busy = 0;
+ if (busy)
+ return 0;
+ busy = 1;
+ pendingcalls_to_do = 0;
+ for (;;) {
+ int i;
+ int (*func)(void *);
+ void *arg;
+ i = pendingfirst;
+ if (i == pendinglast)
+ break; /* Queue empty */
+ func = pendingcalls[i].func;
+ arg = pendingcalls[i].arg;
+ pendingfirst = (i + 1) % NPENDINGCALLS;
+ if (func(arg) < 0) {
+ busy = 0;
+ pendingcalls_to_do = 1; /* We're not done yet */
+ return -1;
+ }
+ }
+ busy = 0;
+ return 0;
+}
+
+#endif /* WITH_THREAD */
+
+
+/* The interpreter's recursion limit */
+
+#ifndef Py_DEFAULT_RECURSION_LIMIT
+#define Py_DEFAULT_RECURSION_LIMIT 1000
+#endif
+static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
+int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
+
+int
+Py_GetRecursionLimit(void)
+{
+ return recursion_limit;
+}
+
+void
+Py_SetRecursionLimit(int new_limit)
+{
+ recursion_limit = new_limit;
+ _Py_CheckRecursionLimit = recursion_limit;
+}
+
+/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall()
+ if the recursion_depth reaches _Py_CheckRecursionLimit.
+ If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit
+ to guarantee that _Py_CheckRecursiveCall() is regularly called.
+ Without USE_STACKCHECK, there is no need for this. */
+int
+_Py_CheckRecursiveCall(const char *where)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+#ifdef USE_STACKCHECK
+ if (PyOS_CheckStack()) {
+ --tstate->recursion_depth;
+ PyErr_SetString(PyExc_MemoryError, "Stack overflow");
+ return -1;
+ }
+#endif
+ if (tstate->recursion_depth > recursion_limit) {
+ --tstate->recursion_depth;
+ PyErr_Format(PyExc_RuntimeError,
+ "maximum recursion depth exceeded%s",
+ where);
+ return -1;
+ }
+ _Py_CheckRecursionLimit = recursion_limit;
+ return 0;
+}
+
+/* Status code for main loop (reason for stack unwind) */
+enum why_code {
+ WHY_NOT = 0x0001, /* No error */
+ WHY_EXCEPTION = 0x0002, /* Exception occurred */
+ WHY_RERAISE = 0x0004, /* Exception re-raised by 'finally' */
+ WHY_RETURN = 0x0008, /* 'return' statement */
+ WHY_BREAK = 0x0010, /* 'break' statement */
+ WHY_CONTINUE = 0x0020, /* 'continue' statement */
+ WHY_YIELD = 0x0040 /* 'yield' operator */
+};
+
+static enum why_code do_raise(PyObject *, PyObject *, PyObject *);
+static int unpack_iterable(PyObject *, int, PyObject **);
+
+/* Records whether tracing is on for any thread. Counts the number of
+ threads for which tstate->c_tracefunc is non-NULL, so if the value
+ is 0, we know we don't have to check this thread's c_tracefunc.
+ This speeds up the if statement in PyEval_EvalFrameEx() after
+ fast_next_opcode*/
+static int _Py_TracingPossible = 0;
+
+/* for manipulating the thread switch and periodic "stuff" - used to be
+ per thread, now just a pair o' globals */
+int _Py_CheckInterval = 100;
+volatile int _Py_Ticker = 0; /* so that we hit a "tick" first thing */
+
+PyObject *
+PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
+{
+ return PyEval_EvalCodeEx(co,
+ globals, locals,
+ (PyObject **)NULL, 0,
+ (PyObject **)NULL, 0,
+ (PyObject **)NULL, 0,
+ NULL);
+}
+
+
+/* Interpreter main loop */
+
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f) {
+ /* This is for backward compatibility with extension modules that
+ used this API; core interpreter code should call
+ PyEval_EvalFrameEx() */
+ return PyEval_EvalFrameEx(f, 0);
+}
+
+PyObject *
+PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
+{
+#ifdef DYNAMIC_EXECUTION_PROFILE
+ #undef USE_COMPUTED_GOTOS
+#endif
+#ifdef HAVE_COMPUTED_GOTOS
+ #ifndef USE_COMPUTED_GOTOS
+ #if defined(__clang__) && (__clang_major__ < 5)
+ /* Computed gotos caused significant performance regression
+ * with clang < 5.0.
+ * https://bugs.python.org/issue32616
+ */
+ #define USE_COMPUTED_GOTOS 0
+ #else
+ #define USE_COMPUTED_GOTOS 1
+ #endif
+ #endif
+#else
+ #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS
+ #error "Computed gotos are not supported on this compiler."
+ #endif
+ #undef USE_COMPUTED_GOTOS
+ #define USE_COMPUTED_GOTOS 0
+#endif
+#if USE_COMPUTED_GOTOS
+/* Import the static jump table */
+#include "opcode_targets.h"
+
+ /* This macro is used when several opcodes defer to the same implementation
+ (e.g. SETUP_LOOP, SETUP_FINALLY) */
+#define TARGET_WITH_IMPL(op, impl) \
+ TARGET_##op: \
+ opcode = op; \
+ oparg = NEXTARG(); \
+ case op: \
+ goto impl; \
+
+#define TARGET_WITH_IMPL_NOARG(op, impl) \
+ TARGET_##op: \
+ opcode = op; \
+ case op: \
+ goto impl; \
+
+#define TARGET_NOARG(op) \
+ TARGET_##op: \
+ opcode = op; \
+ case op:\
+
+#define TARGET(op) \
+ TARGET_##op: \
+ opcode = op; \
+ oparg = NEXTARG(); \
+ case op:\
+
+
+#define DISPATCH() \
+ { \
+ int _tick = _Py_Ticker - 1; \
+ _Py_Ticker = _tick; \
+ if (_tick >= 0) { \
+ FAST_DISPATCH(); \
+ } \
+ continue; \
+ }
+
+#ifdef LLTRACE
+#define FAST_DISPATCH() \
+ { \
+ if (!lltrace && !_Py_TracingPossible) { \
+ f->f_lasti = INSTR_OFFSET(); \
+ goto *opcode_targets[*next_instr++]; \
+ } \
+ goto fast_next_opcode; \
+ }
+#else
+#define FAST_DISPATCH() { \
+ if (!_Py_TracingPossible) { \
+ f->f_lasti = INSTR_OFFSET(); \
+ goto *opcode_targets[*next_instr++]; \
+ } \
+ goto fast_next_opcode;\
+}
+#endif
+
+#else
+#define TARGET(op) \
+ case op:
+#define TARGET_WITH_IMPL(op, impl) \
+ /* silence compiler warnings about `impl` unused */ \
+ if (0) goto impl; \
+ case op:\
+
+#define TARGET_NOARG(op) \
+ case op:\
+
+#define TARGET_WITH_IMPL_NOARG(op, impl) \
+ if (0) goto impl; \
+ case op:\
+
+#define DISPATCH() continue
+#define FAST_DISPATCH() goto fast_next_opcode
+#endif
+
+
+#ifdef DXPAIRS
+ int lastopcode = 0;
+#endif
+ register PyObject **stack_pointer; /* Next free slot in value stack */
+ register unsigned char *next_instr;
+ register int opcode; /* Current opcode */
+ register int oparg; /* Current opcode argument, if any */
+ register enum why_code why; /* Reason for block stack unwind */
+ register int err; /* Error status -- nonzero if error */
+ register PyObject *x; /* Result object -- NULL if error */
+ register PyObject *v; /* Temporary objects popped off stack */
+ register PyObject *w;
+ register PyObject *u;
+ register PyObject *t;
+ register PyObject *stream = NULL; /* for PRINT opcodes */
+ register PyObject **fastlocals, **freevars;
+ PyObject *retval = NULL; /* Return value */
+ PyThreadState *tstate = PyThreadState_GET();
+ PyCodeObject *co;
+
+ /* when tracing we set things up so that
+
+ not (instr_lb <= current_bytecode_offset < instr_ub)
+
+ is true when the line being executed has changed. The
+ initial values are such as to make this false the first
+ time it is tested. */
+ int instr_ub = -1, instr_lb = 0, instr_prev = -1;
+
+ unsigned char *first_instr;
+ PyObject *names;
+ PyObject *consts;
+#if defined(Py_DEBUG) || defined(LLTRACE)
+ /* Make it easier to find out where we are with a debugger */
+#ifdef __GNUC__
+ char *filename __attribute__((unused));
+#else
+ char *filename;
+#endif
+#endif
+
+/* Tuple access macros */
+
+#ifndef Py_DEBUG
+#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))
+#else
+#define GETITEM(v, i) PyTuple_GetItem((v), (i))
+#endif
+
+#ifdef WITH_TSC
+/* Use Pentium timestamp counter to mark certain events:
+ inst0 -- beginning of switch statement for opcode dispatch
+ inst1 -- end of switch statement (may be skipped)
+ loop0 -- the top of the mainloop
+ loop1 -- place where control returns again to top of mainloop
+ (may be skipped)
+ intr1 -- beginning of long interruption
+ intr2 -- end of long interruption
+
+ Many opcodes call out to helper C functions. In some cases, the
+ time in those functions should be counted towards the time for the
+ opcode, but not in all cases. For example, a CALL_FUNCTION opcode
+ calls another Python function; there's no point in charge all the
+ bytecode executed by the called function to the caller.
+
+ It's hard to make a useful judgement statically. In the presence
+ of operator overloading, it's impossible to tell if a call will
+ execute new Python code or not.
+
+ It's a case-by-case judgement. I'll use intr1 for the following
+ cases:
+
+ EXEC_STMT
+ IMPORT_STAR
+ IMPORT_FROM
+ CALL_FUNCTION (and friends)
+
+ */
+ uint64 inst0, inst1, loop0, loop1, intr0 = 0, intr1 = 0;
+ int ticked = 0;
+
+ READ_TIMESTAMP(inst0);
+ READ_TIMESTAMP(inst1);
+ READ_TIMESTAMP(loop0);
+ READ_TIMESTAMP(loop1);
+
+ /* shut up the compiler */
+ opcode = 0;
+#endif
+
+/* Code access macros */
+
+#define INSTR_OFFSET() ((int)(next_instr - first_instr))
+#define NEXTOP() (*next_instr++)
+#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
+#define PEEKARG() ((next_instr[2]<<8) + next_instr[1])
+#define JUMPTO(x) (next_instr = first_instr + (x))
+#define JUMPBY(x) (next_instr += (x))
+
+/* OpCode prediction macros
+ Some opcodes tend to come in pairs thus making it possible to
+ predict the second code when the first is run. For example,
+ GET_ITER is often followed by FOR_ITER. And FOR_ITER is often
+ followed by STORE_FAST or UNPACK_SEQUENCE.
+
+ Verifying the prediction costs a single high-speed test of a register
+ variable against a constant. If the pairing was good, then the
+ processor's own internal branch predication has a high likelihood of
+ success, resulting in a nearly zero-overhead transition to the
+ next opcode. A successful prediction saves a trip through the eval-loop
+ including its two unpredictable branches, the HAS_ARG test and the
+ switch-case. Combined with the processor's internal branch prediction,
+ a successful PREDICT has the effect of making the two opcodes run as if
+ they were a single new opcode with the bodies combined.
+
+ If collecting opcode statistics, your choices are to either keep the
+ predictions turned-on and interpret the results as if some opcodes
+ had been combined or turn-off predictions so that the opcode frequency
+ counter updates for both opcodes.
+*/
+
+
+#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
+#define PREDICT(op) if (0) goto PRED_##op
+#define PREDICTED(op) PRED_##op:
+#define PREDICTED_WITH_ARG(op) PRED_##op:
+#else
+#define PREDICT(op) if (*next_instr == op) goto PRED_##op
+#define PREDICTED(op) PRED_##op: next_instr++
+#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3
+#endif
+
+
+/* Stack manipulation macros */
+
+/* The stack can grow at most MAXINT deep, as co_nlocals and
+ co_stacksize are ints. */
+#define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack))
+#define EMPTY() (STACK_LEVEL() == 0)
+#define TOP() (stack_pointer[-1])
+#define SECOND() (stack_pointer[-2])
+#define THIRD() (stack_pointer[-3])
+#define FOURTH() (stack_pointer[-4])
+#define PEEK(n) (stack_pointer[-(n)])
+#define SET_TOP(v) (stack_pointer[-1] = (v))
+#define SET_SECOND(v) (stack_pointer[-2] = (v))
+#define SET_THIRD(v) (stack_pointer[-3] = (v))
+#define SET_FOURTH(v) (stack_pointer[-4] = (v))
+#define SET_VALUE(n, v) (stack_pointer[-(n)] = (v))
+#define BASIC_STACKADJ(n) (stack_pointer += n)
+#define BASIC_PUSH(v) (*stack_pointer++ = (v))
+#define BASIC_POP() (*--stack_pointer)
+
+#ifdef LLTRACE
+#define PUSH(v) { (void)(BASIC_PUSH(v), \
+ lltrace && prtrace(TOP(), "push")); \
+ assert(STACK_LEVEL() <= co->co_stacksize); }
+#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), \
+ BASIC_POP())
+#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \
+ lltrace && prtrace(TOP(), "stackadj")); \
+ assert(STACK_LEVEL() <= co->co_stacksize); }
+#define EXT_POP(STACK_POINTER) ((void)(lltrace && \
+ prtrace((STACK_POINTER)[-1], "ext_pop")), \
+ *--(STACK_POINTER))
+#else
+#define PUSH(v) BASIC_PUSH(v)
+#define POP() BASIC_POP()
+#define STACKADJ(n) BASIC_STACKADJ(n)
+#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
+#endif
+
+/* Local variable macros */
+
+#define GETLOCAL(i) (fastlocals[i])
+
+/* The SETLOCAL() macro must not DECREF the local variable in-place and
+ then store the new value; it must copy the old value to a temporary
+ value, then store the new value, and then DECREF the temporary value.
+ This is because it is possible that during the DECREF the frame is
+ accessed by other code (e.g. a __del__ method or gc.collect()) and the
+ variable would be pointing to already-freed memory. */
+#define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \
+ GETLOCAL(i) = value; \
+ Py_XDECREF(tmp); } while (0)
+
+/* Start of code */
+
+ if (f == NULL)
+ return NULL;
+
+ /* push frame */
+ if (Py_EnterRecursiveCall(""))
+ return NULL;
+
+ tstate->frame = f;
+
+ if (tstate->use_tracing) {
+ if (tstate->c_tracefunc != NULL) {
+ /* tstate->c_tracefunc, if defined, is a
+ function that will be called on *every* entry
+ to a code block. Its return value, if not
+ None, is a function that will be called at
+ the start of each executed line of code.
+ (Actually, the function must return itself
+ in order to continue tracing.) The trace
+ functions are called with three arguments:
+ a pointer to the current frame, a string
+ indicating why the function is called, and
+ an argument which depends on the situation.
+ The global trace function is also called
+ whenever an exception is detected. */
+ if (call_trace_protected(tstate->c_tracefunc,
+ tstate->c_traceobj,
+ f, PyTrace_CALL, Py_None)) {
+ /* Trace function raised an error */
+ goto exit_eval_frame;
+ }
+ }
+ if (tstate->c_profilefunc != NULL) {
+ /* Similar for c_profilefunc, except it needn't
+ return itself and isn't called for "line" events */
+ if (call_trace_protected(tstate->c_profilefunc,
+ tstate->c_profileobj,
+ f, PyTrace_CALL, Py_None)) {
+ /* Profile function raised an error */
+ goto exit_eval_frame;
+ }
+ }
+ }
+
+ co = f->f_code;
+ names = co->co_names;
+ consts = co->co_consts;
+ fastlocals = f->f_localsplus;
+ freevars = f->f_localsplus + co->co_nlocals;
+ first_instr = (unsigned char*) PyString_AS_STRING(co->co_code);
+ /* An explanation is in order for the next line.
+
+ f->f_lasti now refers to the index of the last instruction
+ executed. You might think this was obvious from the name, but
+ this wasn't always true before 2.3! PyFrame_New now sets
+ f->f_lasti to -1 (i.e. the index *before* the first instruction)
+ and YIELD_VALUE doesn't fiddle with f_lasti any more. So this
+ does work. Promise.
+
+ When the PREDICT() macros are enabled, some opcode pairs follow in
+ direct succession without updating f->f_lasti. A successful
+ prediction effectively links the two codes together as if they
+ were a single new opcode; accordingly,f->f_lasti will point to
+ the first code in the pair (for instance, GET_ITER followed by
+ FOR_ITER is effectively a single opcode and f->f_lasti will point
+ at to the beginning of the combined pair.)
+ */
+ next_instr = first_instr + f->f_lasti + 1;
+ stack_pointer = f->f_stacktop;
+ assert(stack_pointer != NULL);
+ f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
+
+#ifdef LLTRACE
+ lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL;
+#endif
+#if defined(Py_DEBUG) || defined(LLTRACE)
+ filename = PyString_AsString(co->co_filename);
+#endif
+
+ why = WHY_NOT;
+ err = 0;
+ x = Py_None; /* Not a reference, just anything non-NULL */
+ w = NULL;
+
+ if (throwflag) { /* support for generator.throw() */
+ why = WHY_EXCEPTION;
+ goto on_error;
+ }
+
+ for (;;) {
+#ifdef WITH_TSC
+ if (inst1 == 0) {
+ /* Almost surely, the opcode executed a break
+ or a continue, preventing inst1 from being set
+ on the way out of the loop.
+ */
+ READ_TIMESTAMP(inst1);
+ loop1 = inst1;
+ }
+ dump_tsc(opcode, ticked, inst0, inst1, loop0, loop1,
+ intr0, intr1);
+ ticked = 0;
+ inst1 = 0;
+ intr0 = 0;
+ intr1 = 0;
+ READ_TIMESTAMP(loop0);
+#endif
+ assert(stack_pointer >= f->f_valuestack); /* else underflow */
+ assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */
+
+ /* Do periodic things. Doing this every time through
+ the loop would add too much overhead, so we do it
+ only every Nth instruction. We also do it if
+ ``pendingcalls_to_do'' is set, i.e. when an asynchronous
+ event needs attention (e.g. a signal handler or
+ async I/O handler); see Py_AddPendingCall() and
+ Py_MakePendingCalls() above. */
+
+ if (--_Py_Ticker < 0) {
+ if (*next_instr == SETUP_FINALLY) {
+ /* Make the last opcode before
+ a try: finally: block uninterruptible. */
+ goto fast_next_opcode;
+ }
+ _Py_Ticker = _Py_CheckInterval;
+ tstate->tick_counter++;
+#ifdef WITH_TSC
+ ticked = 1;
+#endif
+ if (pendingcalls_to_do) {
+ if (Py_MakePendingCalls() < 0) {
+ why = WHY_EXCEPTION;
+ goto on_error;
+ }
+ if (pendingcalls_to_do)
+ /* MakePendingCalls() didn't succeed.
+ Force early re-execution of this
+ "periodic" code, possibly after
+ a thread switch */
+ _Py_Ticker = 0;
+ }
+#ifdef WITH_THREAD
+ if (interpreter_lock) {
+ /* Give another thread a chance */
+
+ if (PyThreadState_Swap(NULL) != tstate)
+ Py_FatalError("ceval: tstate mix-up");
+ PyThread_release_lock(interpreter_lock);
+
+ /* Other threads may run now */
+
+ PyThread_acquire_lock(interpreter_lock, 1);
+
+ if (PyThreadState_Swap(tstate) != NULL)
+ Py_FatalError("ceval: orphan tstate");
+
+ /* Check for thread interrupts */
+
+ if (tstate->async_exc != NULL) {
+ x = tstate->async_exc;
+ tstate->async_exc = NULL;
+ PyErr_SetNone(x);
+ Py_DECREF(x);
+ why = WHY_EXCEPTION;
+ goto on_error;
+ }
+ }
+#endif
+ }
+
+ fast_next_opcode:
+ f->f_lasti = INSTR_OFFSET();
+
+ /* line-by-line tracing support */
+
+ if (_Py_TracingPossible &&
+ tstate->c_tracefunc != NULL && !tstate->tracing) {
+ /* see maybe_call_line_trace
+ for expository comments */
+ f->f_stacktop = stack_pointer;
+
+ err = maybe_call_line_trace(tstate->c_tracefunc,
+ tstate->c_traceobj,
+ f, &instr_lb, &instr_ub,
+ &instr_prev);
+ /* Reload possibly changed frame fields */
+ JUMPTO(f->f_lasti);
+ if (f->f_stacktop != NULL) {
+ stack_pointer = f->f_stacktop;
+ f->f_stacktop = NULL;
+ }
+ if (err) {
+ /* trace function raised an exception */
+ goto on_error;
+ }
+ }
+
+ /* Extract opcode and argument */
+
+ opcode = NEXTOP();
+ oparg = 0; /* allows oparg to be stored in a register because
+ it doesn't have to be remembered across a full loop */
+ if (HAS_ARG(opcode))
+ oparg = NEXTARG();
+ dispatch_opcode:
+#ifdef DYNAMIC_EXECUTION_PROFILE
+#ifdef DXPAIRS
+ dxpairs[lastopcode][opcode]++;
+ lastopcode = opcode;
+#endif
+ dxp[opcode]++;
+#endif
+
+#ifdef LLTRACE
+ /* Instruction tracing */
+
+ if (lltrace) {
+ if (HAS_ARG(opcode)) {
+ printf("%d: %d, %d\n",
+ f->f_lasti, opcode, oparg);
+ }
+ else {
+ printf("%d: %d\n",
+ f->f_lasti, opcode);
+ }
+ }
+#endif
+
+ /* Main switch on opcode */
+ READ_TIMESTAMP(inst0);
+
+ switch (opcode) {
+
+ /* BEWARE!
+ It is essential that any operation that fails sets either
+ x to NULL, err to nonzero, or why to anything but WHY_NOT,
+ and that no operation that succeeds does this! */
+
+ /* case STOP_CODE: this is an error! */
+
+ TARGET_NOARG(NOP)
+ {
+ FAST_DISPATCH();
+ }
+
+ TARGET(LOAD_FAST)
+ {
+ x = GETLOCAL(oparg);
+ if (x != NULL) {
+ Py_INCREF(x);
+ PUSH(x);
+ FAST_DISPATCH();
+ }
+ format_exc_check_arg(PyExc_UnboundLocalError,
+ UNBOUNDLOCAL_ERROR_MSG,
+ PyTuple_GetItem(co->co_varnames, oparg));
+ break;
+ }
+
+ TARGET(LOAD_CONST)
+ {
+ x = GETITEM(consts, oparg);
+ Py_INCREF(x);
+ PUSH(x);
+ FAST_DISPATCH();
+ }
+
+ PREDICTED_WITH_ARG(STORE_FAST);
+ TARGET(STORE_FAST)
+ {
+ v = POP();
+ SETLOCAL(oparg, v);
+ FAST_DISPATCH();
+ }
+
+ TARGET_NOARG(POP_TOP)
+ {
+ v = POP();
+ Py_DECREF(v);
+ FAST_DISPATCH();
+ }
+
+ TARGET_NOARG(ROT_TWO)
+ {
+ v = TOP();
+ w = SECOND();
+ SET_TOP(w);
+ SET_SECOND(v);
+ FAST_DISPATCH();
+ }
+
+ TARGET_NOARG(ROT_THREE)
+ {
+ v = TOP();
+ w = SECOND();
+ x = THIRD();
+ SET_TOP(w);
+ SET_SECOND(x);
+ SET_THIRD(v);
+ FAST_DISPATCH();
+ }
+
+ TARGET_NOARG(ROT_FOUR)
+ {
+ u = TOP();
+ v = SECOND();
+ w = THIRD();
+ x = FOURTH();
+ SET_TOP(v);
+ SET_SECOND(w);
+ SET_THIRD(x);
+ SET_FOURTH(u);
+ FAST_DISPATCH();
+ }
+
+
+ TARGET_NOARG(DUP_TOP)
+ {
+ v = TOP();
+ Py_INCREF(v);
+ PUSH(v);
+ FAST_DISPATCH();
+ }
+
+
+ TARGET(DUP_TOPX)
+ {
+ if (oparg == 2) {
+ x = TOP();
+ Py_INCREF(x);
+ w = SECOND();
+ Py_INCREF(w);
+ STACKADJ(2);
+ SET_TOP(x);
+ SET_SECOND(w);
+ FAST_DISPATCH();
+ } else if (oparg == 3) {
+ x = TOP();
+ Py_INCREF(x);
+ w = SECOND();
+ Py_INCREF(w);
+ v = THIRD();
+ Py_INCREF(v);
+ STACKADJ(3);
+ SET_TOP(x);
+ SET_SECOND(w);
+ SET_THIRD(v);
+ FAST_DISPATCH();
+ }
+ Py_FatalError("invalid argument to DUP_TOPX"
+ " (bytecode corruption?)");
+ /* Never returns, so don't bother to set why. */
+ break;
+ }
+
+ TARGET_NOARG(UNARY_POSITIVE)
+ {
+ v = TOP();
+ x = PyNumber_Positive(v);
+ Py_DECREF(v);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG( UNARY_NEGATIVE)
+ {
+ v = TOP();
+ x = PyNumber_Negative(v);
+ Py_DECREF(v);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(UNARY_NOT)
+ {
+ v = TOP();
+ err = PyObject_IsTrue(v);
+ Py_DECREF(v);
+ if (err == 0) {
+ Py_INCREF(Py_True);
+ SET_TOP(Py_True);
+ DISPATCH();
+ }
+ else if (err > 0) {
+ Py_INCREF(Py_False);
+ SET_TOP(Py_False);
+ err = 0;
+ DISPATCH();
+ }
+ STACKADJ(-1);
+ break;
+ }
+
+ TARGET_NOARG(UNARY_CONVERT)
+ {
+ v = TOP();
+ x = PyObject_Repr(v);
+ Py_DECREF(v);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(UNARY_INVERT)
+ {
+ v = TOP();
+ x = PyNumber_Invert(v);
+ Py_DECREF(v);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_POWER)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Power(v, w, Py_None);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_MULTIPLY)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Multiply(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if(x!=NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_DIVIDE)
+ {
+ if (!_Py_QnewFlag) {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Divide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+ }
+ /* -Qnew is in effect: fall through to BINARY_TRUE_DIVIDE */
+ TARGET_NOARG(BINARY_TRUE_DIVIDE)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_TrueDivide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_FLOOR_DIVIDE)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_FloorDivide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_MODULO)
+ {
+ w = POP();
+ v = TOP();
+ if (PyString_CheckExact(v)
+ && (!PyString_Check(w) || PyString_CheckExact(w))) {
+ /* fast path; string formatting, but not if the RHS is a str subclass
+ (see issue28598) */
+ x = PyString_Format(v, w);
+ } else {
+ x = PyNumber_Remainder(v, w);
+ }
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_ADD)
+ {
+ w = POP();
+ v = TOP();
+ if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
+ /* INLINE: int + int */
+ register long a, b, i;
+ a = PyInt_AS_LONG(v);
+ b = PyInt_AS_LONG(w);
+ /* cast to avoid undefined behaviour
+ on overflow */
+ i = (long)((unsigned long)a + b);
+ if ((i^a) < 0 && (i^b) < 0)
+ goto slow_add;
+ x = PyInt_FromLong(i);
+ }
+ else if (PyString_CheckExact(v) &&
+ PyString_CheckExact(w)) {
+ x = string_concatenate(v, w, f, next_instr);
+ /* string_concatenate consumed the ref to v */
+ goto skip_decref_vx;
+ }
+ else {
+ slow_add:
+ x = PyNumber_Add(v, w);
+ }
+ Py_DECREF(v);
+ skip_decref_vx:
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_SUBTRACT)
+ {
+ w = POP();
+ v = TOP();
+ if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
+ /* INLINE: int - int */
+ register long a, b, i;
+ a = PyInt_AS_LONG(v);
+ b = PyInt_AS_LONG(w);
+ /* cast to avoid undefined behaviour
+ on overflow */
+ i = (long)((unsigned long)a - b);
+ if ((i^a) < 0 && (i^~b) < 0)
+ goto slow_sub;
+ x = PyInt_FromLong(i);
+ }
+ else {
+ slow_sub:
+ x = PyNumber_Subtract(v, w);
+ }
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_SUBSCR)
+ {
+ w = POP();
+ v = TOP();
+ if (PyList_CheckExact(v) && PyInt_CheckExact(w)) {
+ /* INLINE: list[int] */
+ Py_ssize_t i = PyInt_AsSsize_t(w);
+ if (i < 0)
+ i += PyList_GET_SIZE(v);
+ if (i >= 0 && i < PyList_GET_SIZE(v)) {
+ x = PyList_GET_ITEM(v, i);
+ Py_INCREF(x);
+ }
+ else
+ goto slow_get;
+ }
+ else
+ slow_get:
+ x = PyObject_GetItem(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_LSHIFT)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Lshift(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_RSHIFT)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Rshift(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_AND)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_And(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_XOR)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Xor(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(BINARY_OR)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_Or(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET(LIST_APPEND)
+ {
+ w = POP();
+ v = PEEK(oparg);
+ err = PyList_Append(v, w);
+ Py_DECREF(w);
+ if (err == 0) {
+ PREDICT(JUMP_ABSOLUTE);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET(SET_ADD)
+ {
+ w = POP();
+ v = stack_pointer[-oparg];
+ err = PySet_Add(v, w);
+ Py_DECREF(w);
+ if (err == 0) {
+ PREDICT(JUMP_ABSOLUTE);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_POWER)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlacePower(v, w, Py_None);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_MULTIPLY)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceMultiply(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_DIVIDE)
+ {
+ if (!_Py_QnewFlag) {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceDivide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+ }
+ /* -Qnew is in effect: fall through to
+ INPLACE_TRUE_DIVIDE */
+ TARGET_NOARG(INPLACE_TRUE_DIVIDE)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceTrueDivide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_FLOOR_DIVIDE)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceFloorDivide(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_MODULO)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceRemainder(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_ADD)
+ {
+ w = POP();
+ v = TOP();
+ if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
+ /* INLINE: int + int */
+ register long a, b, i;
+ a = PyInt_AS_LONG(v);
+ b = PyInt_AS_LONG(w);
+ i = a + b;
+ if ((i^a) < 0 && (i^b) < 0)
+ goto slow_iadd;
+ x = PyInt_FromLong(i);
+ }
+ else if (PyString_CheckExact(v) &&
+ PyString_CheckExact(w)) {
+ x = string_concatenate(v, w, f, next_instr);
+ /* string_concatenate consumed the ref to v */
+ goto skip_decref_v;
+ }
+ else {
+ slow_iadd:
+ x = PyNumber_InPlaceAdd(v, w);
+ }
+ Py_DECREF(v);
+ skip_decref_v:
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_SUBTRACT)
+ {
+ w = POP();
+ v = TOP();
+ if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
+ /* INLINE: int - int */
+ register long a, b, i;
+ a = PyInt_AS_LONG(v);
+ b = PyInt_AS_LONG(w);
+ i = a - b;
+ if ((i^a) < 0 && (i^~b) < 0)
+ goto slow_isub;
+ x = PyInt_FromLong(i);
+ }
+ else {
+ slow_isub:
+ x = PyNumber_InPlaceSubtract(v, w);
+ }
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_LSHIFT)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceLshift(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_RSHIFT)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceRshift(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_AND)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceAnd(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_XOR)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceXor(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(INPLACE_OR)
+ {
+ w = POP();
+ v = TOP();
+ x = PyNumber_InPlaceOr(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+
+
+ TARGET_WITH_IMPL_NOARG(SLICE, _slice)
+ TARGET_WITH_IMPL_NOARG(SLICE_1, _slice)
+ TARGET_WITH_IMPL_NOARG(SLICE_2, _slice)
+ TARGET_WITH_IMPL_NOARG(SLICE_3, _slice)
+ _slice:
+ {
+ if ((opcode-SLICE) & 2)
+ w = POP();
+ else
+ w = NULL;
+ if ((opcode-SLICE) & 1)
+ v = POP();
+ else
+ v = NULL;
+ u = TOP();
+ x = apply_slice(u, v, w);
+ Py_DECREF(u);
+ Py_XDECREF(v);
+ Py_XDECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+
+ TARGET_WITH_IMPL_NOARG(STORE_SLICE, _store_slice)
+ TARGET_WITH_IMPL_NOARG(STORE_SLICE_1, _store_slice)
+ TARGET_WITH_IMPL_NOARG(STORE_SLICE_2, _store_slice)
+ TARGET_WITH_IMPL_NOARG(STORE_SLICE_3, _store_slice)
+ _store_slice:
+ {
+ if ((opcode-STORE_SLICE) & 2)
+ w = POP();
+ else
+ w = NULL;
+ if ((opcode-STORE_SLICE) & 1)
+ v = POP();
+ else
+ v = NULL;
+ u = POP();
+ t = POP();
+ err = assign_slice(u, v, w, t); /* u[v:w] = t */
+ Py_DECREF(t);
+ Py_DECREF(u);
+ Py_XDECREF(v);
+ Py_XDECREF(w);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+
+ TARGET_WITH_IMPL_NOARG(DELETE_SLICE, _delete_slice)
+ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_1, _delete_slice)
+ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_2, _delete_slice)
+ TARGET_WITH_IMPL_NOARG(DELETE_SLICE_3, _delete_slice)
+ _delete_slice:
+ {
+ if ((opcode-DELETE_SLICE) & 2)
+ w = POP();
+ else
+ w = NULL;
+ if ((opcode-DELETE_SLICE) & 1)
+ v = POP();
+ else
+ v = NULL;
+ u = POP();
+ err = assign_slice(u, v, w, (PyObject *)NULL);
+ /* del u[v:w] */
+ Py_DECREF(u);
+ Py_XDECREF(v);
+ Py_XDECREF(w);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(STORE_SUBSCR)
+ {
+ w = TOP();
+ v = SECOND();
+ u = THIRD();
+ STACKADJ(-3);
+ /* v[w] = u */
+ err = PyObject_SetItem(v, w, u);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(DELETE_SUBSCR)
+ {
+ w = TOP();
+ v = SECOND();
+ STACKADJ(-2);
+ /* del v[w] */
+ err = PyObject_DelItem(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(PRINT_EXPR)
+ {
+ v = POP();
+ w = PySys_GetObject("displayhook");
+ if (w == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "lost sys.displayhook");
+ err = -1;
+ x = NULL;
+ }
+ if (err == 0) {
+ x = PyTuple_Pack(1, v);
+ if (x == NULL)
+ err = -1;
+ }
+ if (err == 0) {
+ w = PyEval_CallObject(w, x);
+ Py_XDECREF(w);
+ if (w == NULL)
+ err = -1;
+ }
+ Py_DECREF(v);
+ Py_XDECREF(x);
+ break;
+ }
+
+ TARGET_NOARG(PRINT_ITEM_TO)
+ {
+ w = stream = POP();
+ /* fall through to PRINT_ITEM */
+ }
+
+ TARGET_NOARG(PRINT_ITEM)
+ {
+ v = POP();
+ if (stream == NULL || stream == Py_None) {
+ w = PySys_GetObject("stdout");
+ if (w == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "lost sys.stdout");
+ err = -1;
+ }
+ }
+ /* PyFile_SoftSpace() can exececute arbitrary code
+ if sys.stdout is an instance with a __getattr__.
+ If __getattr__ raises an exception, w will
+ be freed, so we need to prevent that temporarily. */
+ Py_XINCREF(w);
+ if (w != NULL && PyFile_SoftSpace(w, 0))
+ err = PyFile_WriteString(" ", w);
+ if (err == 0)
+ err = PyFile_WriteObject(v, w, Py_PRINT_RAW);
+ if (err == 0) {
+ /* XXX move into writeobject() ? */
+ if (PyString_Check(v)) {
+ char *s = PyString_AS_STRING(v);
+ Py_ssize_t len = PyString_GET_SIZE(v);
+ if (len == 0 ||
+ !isspace(Py_CHARMASK(s[len-1])) ||
+ s[len-1] == ' ')
+ PyFile_SoftSpace(w, 1);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(v)) {
+ Py_UNICODE *s = PyUnicode_AS_UNICODE(v);
+ Py_ssize_t len = PyUnicode_GET_SIZE(v);
+ if (len == 0 ||
+ !Py_UNICODE_ISSPACE(s[len-1]) ||
+ s[len-1] == ' ')
+ PyFile_SoftSpace(w, 1);
+ }
+#endif
+ else
+ PyFile_SoftSpace(w, 1);
+ }
+ Py_XDECREF(w);
+ Py_DECREF(v);
+ Py_XDECREF(stream);
+ stream = NULL;
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(PRINT_NEWLINE_TO)
+ {
+ w = stream = POP();
+ /* fall through to PRINT_NEWLINE */
+ }
+
+ TARGET_NOARG(PRINT_NEWLINE)
+ {
+ if (stream == NULL || stream == Py_None)
+ {
+ w = PySys_GetObject("stdout");
+ if (w == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "lost sys.stdout");
+ why = WHY_EXCEPTION;
+ }
+ }
+ if (w != NULL) {
+ /* w.write() may replace sys.stdout, so we
+ * have to keep our reference to it */
+ Py_INCREF(w);
+ err = PyFile_WriteString("\n", w);
+ if (err == 0)
+ PyFile_SoftSpace(w, 0);
+ Py_DECREF(w);
+ }
+ Py_XDECREF(stream);
+ stream = NULL;
+ break;
+ }
+
+#ifdef CASE_TOO_BIG
+ default: switch (opcode) {
+#endif
+
+ TARGET(RAISE_VARARGS)
+ {
+ u = v = w = NULL;
+ switch (oparg) {
+ case 3:
+ u = POP(); /* traceback */
+ /* Fallthrough */
+ case 2:
+ v = POP(); /* value */
+ /* Fallthrough */
+ case 1:
+ w = POP(); /* exc */
+ case 0: /* Fallthrough */
+ why = do_raise(w, v, u);
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "bad RAISE_VARARGS oparg");
+ why = WHY_EXCEPTION;
+ break;
+ }
+ break;
+ }
+
+ TARGET_NOARG(LOAD_LOCALS)
+ {
+ if ((x = f->f_locals) != NULL)
+ {
+ Py_INCREF(x);
+ PUSH(x);
+ DISPATCH();
+ }
+ PyErr_SetString(PyExc_SystemError, "no locals");
+ break;
+ }
+
+ TARGET_NOARG(RETURN_VALUE)
+ {
+ retval = POP();
+ why = WHY_RETURN;
+ goto fast_block_end;
+ }
+
+ TARGET_NOARG(YIELD_VALUE)
+ {
+ retval = POP();
+ f->f_stacktop = stack_pointer;
+ why = WHY_YIELD;
+ goto fast_yield;
+ }
+
+ TARGET_NOARG(EXEC_STMT)
+ {
+ w = TOP();
+ v = SECOND();
+ u = THIRD();
+ STACKADJ(-3);
+ READ_TIMESTAMP(intr0);
+ err = exec_statement(f, u, v, w);
+ READ_TIMESTAMP(intr1);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ break;
+ }
+
+ TARGET_NOARG(POP_BLOCK)
+ {
+ {
+ PyTryBlock *b = PyFrame_BlockPop(f);
+ while (STACK_LEVEL() > b->b_level) {
+ v = POP();
+ Py_DECREF(v);
+ }
+ }
+ DISPATCH();
+ }
+
+ PREDICTED(END_FINALLY);
+ TARGET_NOARG(END_FINALLY)
+ {
+ v = POP();
+ if (PyInt_Check(v)) {
+ why = (enum why_code) PyInt_AS_LONG(v);
+ assert(why != WHY_YIELD);
+ if (why == WHY_RETURN ||
+ why == WHY_CONTINUE)
+ retval = POP();
+ }
+ else if (PyExceptionClass_Check(v) ||
+ PyString_Check(v)) {
+ w = POP();
+ u = POP();
+ PyErr_Restore(v, w, u);
+ why = WHY_RERAISE;
+ break;
+ }
+ else if (v != Py_None) {
+ PyErr_SetString(PyExc_SystemError,
+ "'finally' pops bad exception");
+ why = WHY_EXCEPTION;
+ }
+ Py_DECREF(v);
+ break;
+ }
+
+ TARGET_NOARG(BUILD_CLASS)
+ {
+ u = TOP();
+ v = SECOND();
+ w = THIRD();
+ STACKADJ(-2);
+ x = build_class(u, v, w);
+ SET_TOP(x);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ break;
+ }
+
+ TARGET(STORE_NAME)
+ {
+ w = GETITEM(names, oparg);
+ v = POP();
+ if ((x = f->f_locals) != NULL) {
+ if (PyDict_CheckExact(x))
+ err = PyDict_SetItem(x, w, v);
+ else
+ err = PyObject_SetItem(x, w, v);
+ Py_DECREF(v);
+ if (err == 0) DISPATCH();
+ break;
+ }
+ t = PyObject_Repr(w);
+ if (t == NULL)
+ break;
+ PyErr_Format(PyExc_SystemError,
+ "no locals found when storing %s",
+ PyString_AS_STRING(t));
+ Py_DECREF(t);
+ break;
+ }
+
+ TARGET(DELETE_NAME)
+ {
+ w = GETITEM(names, oparg);
+ if ((x = f->f_locals) != NULL) {
+ if ((err = PyObject_DelItem(x, w)) != 0)
+ format_exc_check_arg(PyExc_NameError,
+ NAME_ERROR_MSG,
+ w);
+ break;
+ }
+ t = PyObject_Repr(w);
+ if (t == NULL)
+ break;
+ PyErr_Format(PyExc_SystemError,
+ "no locals when deleting %s",
+ PyString_AS_STRING(w));
+ Py_DECREF(t);
+ break;
+ }
+
+ PREDICTED_WITH_ARG(UNPACK_SEQUENCE);
+ TARGET(UNPACK_SEQUENCE)
+ {
+ v = POP();
+ if (PyTuple_CheckExact(v) &&
+ PyTuple_GET_SIZE(v) == oparg) {
+ PyObject **items = \
+ ((PyTupleObject *)v)->ob_item;
+ while (oparg--) {
+ w = items[oparg];
+ Py_INCREF(w);
+ PUSH(w);
+ }
+ Py_DECREF(v);
+ DISPATCH();
+ } else if (PyList_CheckExact(v) &&
+ PyList_GET_SIZE(v) == oparg) {
+ PyObject **items = \
+ ((PyListObject *)v)->ob_item;
+ while (oparg--) {
+ w = items[oparg];
+ Py_INCREF(w);
+ PUSH(w);
+ }
+ } else if (unpack_iterable(v, oparg,
+ stack_pointer + oparg)) {
+ STACKADJ(oparg);
+ } else {
+ /* unpack_iterable() raised an exception */
+ why = WHY_EXCEPTION;
+ }
+ Py_DECREF(v);
+ break;
+ }
+
+
+ TARGET(STORE_ATTR)
+ {
+ w = GETITEM(names, oparg);
+ v = TOP();
+ u = SECOND();
+ STACKADJ(-2);
+ err = PyObject_SetAttr(v, w, u); /* v.w = u */
+ Py_DECREF(v);
+ Py_DECREF(u);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET(DELETE_ATTR)
+ {
+ w = GETITEM(names, oparg);
+ v = POP();
+ err = PyObject_SetAttr(v, w, (PyObject *)NULL);
+ /* del v.w */
+ Py_DECREF(v);
+ break;
+ }
+
+
+ TARGET(STORE_GLOBAL)
+ {
+ w = GETITEM(names, oparg);
+ v = POP();
+ err = PyDict_SetItem(f->f_globals, w, v);
+ Py_DECREF(v);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET(DELETE_GLOBAL)
+ {
+ w = GETITEM(names, oparg);
+ if ((err = PyDict_DelItem(f->f_globals, w)) != 0)
+ format_exc_check_arg(
+ PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w);
+ break;
+ }
+
+ TARGET(LOAD_NAME)
+ {
+ w = GETITEM(names, oparg);
+ if ((v = f->f_locals) == NULL) {
+ why = WHY_EXCEPTION;
+ t = PyObject_Repr(w);
+ if (t == NULL)
+ break;
+ PyErr_Format(PyExc_SystemError,
+ "no locals when loading %s",
+ PyString_AS_STRING(w));
+ Py_DECREF(t);
+ break;
+ }
+ if (PyDict_CheckExact(v)) {
+ x = PyDict_GetItem(v, w);
+ Py_XINCREF(x);
+ }
+ else {
+ x = PyObject_GetItem(v, w);
+ if (x == NULL && PyErr_Occurred()) {
+ if (!PyErr_ExceptionMatches(
+ PyExc_KeyError))
+ break;
+ PyErr_Clear();
+ }
+ }
+ if (x == NULL) {
+ x = PyDict_GetItem(f->f_globals, w);
+ if (x == NULL) {
+ x = PyDict_GetItem(f->f_builtins, w);
+ if (x == NULL) {
+ format_exc_check_arg(
+ PyExc_NameError,
+ NAME_ERROR_MSG, w);
+ break;
+ }
+ }
+ Py_INCREF(x);
+ }
+ PUSH(x);
+ DISPATCH();
+ }
+
+ TARGET(LOAD_GLOBAL)
+ {
+ w = GETITEM(names, oparg);
+ if (PyString_CheckExact(w)) {
+ /* Inline the PyDict_GetItem() calls.
+ WARNING: this is an extreme speed hack.
+ Do not try this at home. */
+ long hash = ((PyStringObject *)w)->ob_shash;
+ if (hash != -1) {
+ PyDictObject *d;
+ PyDictEntry *e;
+ d = (PyDictObject *)(f->f_globals);
+ e = d->ma_lookup(d, w, hash);
+ if (e == NULL) {
+ x = NULL;
+ break;
+ }
+ x = e->me_value;
+ if (x != NULL) {
+ Py_INCREF(x);
+ PUSH(x);
+ DISPATCH();
+ }
+ d = (PyDictObject *)(f->f_builtins);
+ e = d->ma_lookup(d, w, hash);
+ if (e == NULL) {
+ x = NULL;
+ break;
+ }
+ x = e->me_value;
+ if (x != NULL) {
+ Py_INCREF(x);
+ PUSH(x);
+ DISPATCH();
+ }
+ goto load_global_error;
+ }
+ }
+ /* This is the un-inlined version of the code above */
+ x = PyDict_GetItem(f->f_globals, w);
+ if (x == NULL) {
+ x = PyDict_GetItem(f->f_builtins, w);
+ if (x == NULL) {
+ load_global_error:
+ format_exc_check_arg(
+ PyExc_NameError,
+ GLOBAL_NAME_ERROR_MSG, w);
+ break;
+ }
+ }
+ Py_INCREF(x);
+ PUSH(x);
+ DISPATCH();
+ }
+
+ TARGET(DELETE_FAST)
+ {
+ x = GETLOCAL(oparg);
+ if (x != NULL) {
+ SETLOCAL(oparg, NULL);
+ DISPATCH();
+ }
+ format_exc_check_arg(
+ PyExc_UnboundLocalError,
+ UNBOUNDLOCAL_ERROR_MSG,
+ PyTuple_GetItem(co->co_varnames, oparg)
+ );
+ break;
+ }
+
+ TARGET(LOAD_CLOSURE)
+ {
+ x = freevars[oparg];
+ Py_INCREF(x);
+ PUSH(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET(LOAD_DEREF)
+ {
+ x = freevars[oparg];
+ w = PyCell_Get(x);
+ if (w != NULL) {
+ PUSH(w);
+ DISPATCH();
+ }
+ err = -1;
+ /* Don't stomp existing exception */
+ if (PyErr_Occurred())
+ break;
+ if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
+ v = PyTuple_GET_ITEM(co->co_cellvars,
+ oparg);
+ format_exc_check_arg(
+ PyExc_UnboundLocalError,
+ UNBOUNDLOCAL_ERROR_MSG,
+ v);
+ } else {
+ v = PyTuple_GET_ITEM(co->co_freevars, oparg -
+ PyTuple_GET_SIZE(co->co_cellvars));
+ format_exc_check_arg(PyExc_NameError,
+ UNBOUNDFREE_ERROR_MSG, v);
+ }
+ break;
+ }
+
+ TARGET(STORE_DEREF)
+ {
+ w = POP();
+ x = freevars[oparg];
+ PyCell_Set(x, w);
+ Py_DECREF(w);
+ DISPATCH();
+ }
+
+ TARGET(BUILD_TUPLE)
+ {
+ x = PyTuple_New(oparg);
+ if (x != NULL) {
+ for (; --oparg >= 0;) {
+ w = POP();
+ PyTuple_SET_ITEM(x, oparg, w);
+ }
+ PUSH(x);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET(BUILD_LIST)
+ {
+ x = PyList_New(oparg);
+ if (x != NULL) {
+ for (; --oparg >= 0;) {
+ w = POP();
+ PyList_SET_ITEM(x, oparg, w);
+ }
+ PUSH(x);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET(BUILD_SET)
+ {
+ int i;
+ x = PySet_New(NULL);
+ if (x != NULL) {
+ for (i = oparg; i > 0; i--) {
+ w = PEEK(i);
+ if (err == 0)
+ err = PySet_Add(x, w);
+ Py_DECREF(w);
+ }
+ STACKADJ(-oparg);
+ if (err != 0) {
+ Py_DECREF(x);
+ break;
+ }
+ PUSH(x);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET(BUILD_MAP)
+ {
+ x = _PyDict_NewPresized((Py_ssize_t)oparg);
+ PUSH(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(STORE_MAP)
+ {
+ w = TOP(); /* key */
+ u = SECOND(); /* value */
+ v = THIRD(); /* dict */
+ STACKADJ(-2);
+ assert (PyDict_CheckExact(v));
+ err = PyDict_SetItem(v, w, u); /* v[w] = u */
+ Py_DECREF(u);
+ Py_DECREF(w);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET(MAP_ADD)
+ {
+ w = TOP(); /* key */
+ u = SECOND(); /* value */
+ STACKADJ(-2);
+ v = stack_pointer[-oparg]; /* dict */
+ assert (PyDict_CheckExact(v));
+ err = PyDict_SetItem(v, w, u); /* v[w] = u */
+ Py_DECREF(u);
+ Py_DECREF(w);
+ if (err == 0) {
+ PREDICT(JUMP_ABSOLUTE);
+ DISPATCH();
+ }
+ break;
+ }
+
+ TARGET(LOAD_ATTR)
+ {
+ w = GETITEM(names, oparg);
+ v = TOP();
+ x = PyObject_GetAttr(v, w);
+ Py_DECREF(v);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET(COMPARE_OP)
+ {
+ w = POP();
+ v = TOP();
+ if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
+ /* INLINE: cmp(int, int) */
+ register long a, b;
+ register int res;
+ a = PyInt_AS_LONG(v);
+ b = PyInt_AS_LONG(w);
+ switch (oparg) {
+ case PyCmp_LT: res = a < b; break;
+ case PyCmp_LE: res = a <= b; break;
+ case PyCmp_EQ: res = a == b; break;
+ case PyCmp_NE: res = a != b; break;
+ case PyCmp_GT: res = a > b; break;
+ case PyCmp_GE: res = a >= b; break;
+ case PyCmp_IS: res = v == w; break;
+ case PyCmp_IS_NOT: res = v != w; break;
+ default: goto slow_compare;
+ }
+ x = res ? Py_True : Py_False;
+ Py_INCREF(x);
+ }
+ else {
+ slow_compare:
+ x = cmp_outcome(oparg, v, w);
+ }
+ Py_DECREF(v);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x == NULL) break;
+ PREDICT(POP_JUMP_IF_FALSE);
+ PREDICT(POP_JUMP_IF_TRUE);
+ DISPATCH();
+ }
+
+ TARGET(IMPORT_NAME)
+ {
+ long res;
+ w = GETITEM(names, oparg);
+ x = PyDict_GetItemString(f->f_builtins, "__import__");
+ if (x == NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "__import__ not found");
+ break;
+ }
+ Py_INCREF(x);
+ v = POP();
+ u = TOP();
+ res = PyInt_AsLong(u);
+ if (res != -1 || PyErr_Occurred()) {
+ if (res == -1) {
+ assert(PyErr_Occurred());
+ PyErr_Clear();
+ }
+ w = PyTuple_Pack(5,
+ w,
+ f->f_globals,
+ f->f_locals == NULL ?
+ Py_None : f->f_locals,
+ v,
+ u);
+ }
+ else
+ w = PyTuple_Pack(4,
+ w,
+ f->f_globals,
+ f->f_locals == NULL ?
+ Py_None : f->f_locals,
+ v);
+ Py_DECREF(v);
+ Py_DECREF(u);
+ if (w == NULL) {
+ u = POP();
+ Py_DECREF(x);
+ x = NULL;
+ break;
+ }
+ READ_TIMESTAMP(intr0);
+ v = x;
+ x = PyEval_CallObject(v, w);
+ Py_DECREF(v);
+ READ_TIMESTAMP(intr1);
+ Py_DECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_NOARG(IMPORT_STAR)
+ {
+ v = POP();
+ PyFrame_FastToLocals(f);
+ if ((x = f->f_locals) == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "no locals found during 'import *'");
+ Py_DECREF(v);
+ break;
+ }
+ READ_TIMESTAMP(intr0);
+ err = import_all_from(x, v);
+ READ_TIMESTAMP(intr1);
+ PyFrame_LocalsToFast(f, 0);
+ Py_DECREF(v);
+ if (err == 0) DISPATCH();
+ break;
+ }
+
+ TARGET(IMPORT_FROM)
+ {
+ w = GETITEM(names, oparg);
+ v = TOP();
+ READ_TIMESTAMP(intr0);
+ x = import_from(v, w);
+ READ_TIMESTAMP(intr1);
+ PUSH(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET(JUMP_FORWARD)
+ {
+ JUMPBY(oparg);
+ FAST_DISPATCH();
+ }
+
+ PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE);
+ TARGET(POP_JUMP_IF_FALSE)
+ {
+ w = POP();
+ if (w == Py_True) {
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_False) {
+ Py_DECREF(w);
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ Py_DECREF(w);
+ if (err > 0)
+ err = 0;
+ else if (err == 0)
+ JUMPTO(oparg);
+ else
+ break;
+ DISPATCH();
+ }
+
+ PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE);
+ TARGET(POP_JUMP_IF_TRUE)
+ {
+ w = POP();
+ if (w == Py_False) {
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_True) {
+ Py_DECREF(w);
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ Py_DECREF(w);
+ if (err > 0) {
+ err = 0;
+ JUMPTO(oparg);
+ }
+ else if (err == 0)
+ ;
+ else
+ break;
+ DISPATCH();
+ }
+
+ TARGET(JUMP_IF_FALSE_OR_POP)
+ {
+ w = TOP();
+ if (w == Py_True) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_False) {
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ if (err > 0) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ err = 0;
+ }
+ else if (err == 0)
+ JUMPTO(oparg);
+ else
+ break;
+ DISPATCH();
+ }
+
+ TARGET(JUMP_IF_TRUE_OR_POP)
+ {
+ w = TOP();
+ if (w == Py_False) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_True) {
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ if (err > 0) {
+ err = 0;
+ JUMPTO(oparg);
+ }
+ else if (err == 0) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ }
+ else
+ break;
+ DISPATCH();
+ }
+
+ PREDICTED_WITH_ARG(JUMP_ABSOLUTE);
+ TARGET(JUMP_ABSOLUTE)
+ {
+ JUMPTO(oparg);
+#if FAST_LOOPS
+ /* Enabling this path speeds-up all while and for-loops by bypassing
+ the per-loop checks for signals. By default, this should be turned-off
+ because it prevents detection of a control-break in tight loops like
+ "while 1: pass". Compile with this option turned-on when you need
+ the speed-up and do not need break checking inside tight loops (ones
+ that contain only instructions ending with goto fast_next_opcode).
+ */
+ goto fast_next_opcode;
+#else
+ DISPATCH();
+#endif
+ }
+
+ TARGET_NOARG(GET_ITER)
+ {
+ /* before: [obj]; after [getiter(obj)] */
+ v = TOP();
+ x = PyObject_GetIter(v);
+ Py_DECREF(v);
+ if (x != NULL) {
+ SET_TOP(x);
+ PREDICT(FOR_ITER);
+ DISPATCH();
+ }
+ STACKADJ(-1);
+ break;
+ }
+
+ PREDICTED_WITH_ARG(FOR_ITER);
+ TARGET(FOR_ITER)
+ {
+ /* before: [iter]; after: [iter, iter()] *or* [] */
+ v = TOP();
+ x = (*v->ob_type->tp_iternext)(v);
+ if (x != NULL) {
+ PUSH(x);
+ PREDICT(STORE_FAST);
+ PREDICT(UNPACK_SEQUENCE);
+ DISPATCH();
+ }
+ if (PyErr_Occurred()) {
+ if (!PyErr_ExceptionMatches(
+ PyExc_StopIteration))
+ break;
+ PyErr_Clear();
+ }
+ /* iterator ended normally */
+ x = v = POP();
+ Py_DECREF(v);
+ JUMPBY(oparg);
+ DISPATCH();
+ }
+
+ TARGET_NOARG(BREAK_LOOP)
+ {
+ why = WHY_BREAK;
+ goto fast_block_end;
+ }
+
+ TARGET(CONTINUE_LOOP)
+ {
+ retval = PyInt_FromLong(oparg);
+ if (!retval) {
+ x = NULL;
+ break;
+ }
+ why = WHY_CONTINUE;
+ goto fast_block_end;
+ }
+
+ TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally)
+ TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally)
+ TARGET(SETUP_FINALLY)
+ _setup_finally:
+ {
+ /* NOTE: If you add any new block-setup opcodes that
+ are not try/except/finally handlers, you may need
+ to update the PyGen_NeedsFinalizing() function.
+ */
+
+ PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
+ STACK_LEVEL());
+ DISPATCH();
+ }
+
+
+
+ TARGET(SETUP_WITH)
+ {
+ {
+ static PyObject *exit, *enter;
+ w = TOP();
+ x = special_lookup(w, "__exit__", &exit);
+ if (!x)
+ break;
+ SET_TOP(x);
+ u = special_lookup(w, "__enter__", &enter);
+ Py_DECREF(w);
+ if (!u) {
+ x = NULL;
+ break;
+ }
+ x = PyObject_CallFunctionObjArgs(u, NULL);
+ Py_DECREF(u);
+ if (!x)
+ break;
+ /* Setup a finally block (SETUP_WITH as a block is
+ equivalent to SETUP_FINALLY except it normalizes
+ the exception) before pushing the result of
+ __enter__ on the stack. */
+ PyFrame_BlockSetup(f, SETUP_WITH, INSTR_OFFSET() + oparg,
+ STACK_LEVEL());
+
+ PUSH(x);
+ DISPATCH();
+ }
+ }
+
+ TARGET_NOARG(WITH_CLEANUP)
+ {
+ /* At the top of the stack are 1-3 values indicating
+ how/why we entered the finally clause:
+ - TOP = None
+ - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval
+ - TOP = WHY_*; no retval below it
+ - (TOP, SECOND, THIRD) = exc_info()
+ Below them is EXIT, the context.__exit__ bound method.
+ In the last case, we must call
+ EXIT(TOP, SECOND, THIRD)
+ otherwise we must call
+ EXIT(None, None, None)
+
+ In all cases, we remove EXIT from the stack, leaving
+ the rest in the same order.
+
+ In addition, if the stack represents an exception,
+ *and* the function call returns a 'true' value, we
+ "zap" this information, to prevent END_FINALLY from
+ re-raising the exception. (But non-local gotos
+ should still be resumed.)
+ */
+
+ PyObject *exit_func;
+
+ u = POP();
+ if (u == Py_None) {
+ exit_func = TOP();
+ SET_TOP(u);
+ v = w = Py_None;
+ }
+ else if (PyInt_Check(u)) {
+ switch(PyInt_AS_LONG(u)) {
+ case WHY_RETURN:
+ case WHY_CONTINUE:
+ /* Retval in TOP. */
+ exit_func = SECOND();
+ SET_SECOND(TOP());
+ SET_TOP(u);
+ break;
+ default:
+ exit_func = TOP();
+ SET_TOP(u);
+ break;
+ }
+ u = v = w = Py_None;
+ }
+ else {
+ v = TOP();
+ w = SECOND();
+ exit_func = THIRD();
+ SET_TOP(u);
+ SET_SECOND(v);
+ SET_THIRD(w);
+ }
+ /* XXX Not the fastest way to call it... */
+ x = PyObject_CallFunctionObjArgs(exit_func, u, v, w,
+ NULL);
+ Py_DECREF(exit_func);
+ if (x == NULL)
+ break; /* Go to error exit */
+
+ if (u != Py_None)
+ err = PyObject_IsTrue(x);
+ else
+ err = 0;
+ Py_DECREF(x);
+
+ if (err < 0)
+ break; /* Go to error exit */
+ else if (err > 0) {
+ err = 0;
+ /* There was an exception and a true return */
+ STACKADJ(-2);
+ Py_INCREF(Py_None);
+ SET_TOP(Py_None);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ } else {
+ /* The stack was rearranged to remove EXIT
+ above. Let END_FINALLY do its thing */
+ }
+ PREDICT(END_FINALLY);
+ break;
+ }
+
+ TARGET(CALL_FUNCTION)
+ {
+ PyObject **sp;
+ PCALL(PCALL_ALL);
+ sp = stack_pointer;
+#ifdef WITH_TSC
+ x = call_function(&sp, oparg, &intr0, &intr1);
+#else
+ x = call_function(&sp, oparg);
+#endif
+ stack_pointer = sp;
+ PUSH(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw)
+ TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw)
+ TARGET(CALL_FUNCTION_VAR_KW)
+ _call_function_var_kw:
+ {
+ int na = oparg & 0xff;
+ int nk = (oparg>>8) & 0xff;
+ int flags = (opcode - CALL_FUNCTION) & 3;
+ int n = na + 2 * nk;
+ PyObject **pfunc, *func, **sp;
+ PCALL(PCALL_ALL);
+ if (flags & CALL_FLAG_VAR)
+ n++;
+ if (flags & CALL_FLAG_KW)
+ n++;
+ pfunc = stack_pointer - n - 1;
+ func = *pfunc;
+
+ if (PyMethod_Check(func)
+ && PyMethod_GET_SELF(func) != NULL) {
+ PyObject *self = PyMethod_GET_SELF(func);
+ Py_INCREF(self);
+ func = PyMethod_GET_FUNCTION(func);
+ Py_INCREF(func);
+ Py_DECREF(*pfunc);
+ *pfunc = self;
+ na++;
+ } else
+ Py_INCREF(func);
+ sp = stack_pointer;
+ READ_TIMESTAMP(intr0);
+ x = ext_do_call(func, &sp, flags, na, nk);
+ READ_TIMESTAMP(intr1);
+ stack_pointer = sp;
+ Py_DECREF(func);
+
+ while (stack_pointer > pfunc) {
+ w = POP();
+ Py_DECREF(w);
+ }
+ PUSH(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+
+ TARGET(MAKE_FUNCTION)
+ {
+ v = POP(); /* code object */
+ x = PyFunction_New(v, f->f_globals);
+ Py_DECREF(v);
+ /* XXX Maybe this should be a separate opcode? */
+ if (x != NULL && oparg > 0) {
+ v = PyTuple_New(oparg);
+ if (v == NULL) {
+ Py_DECREF(x);
+ x = NULL;
+ break;
+ }
+ while (--oparg >= 0) {
+ w = POP();
+ PyTuple_SET_ITEM(v, oparg, w);
+ }
+ err = PyFunction_SetDefaults(x, v);
+ Py_DECREF(v);
+ }
+ PUSH(x);
+ break;
+ }
+
+ TARGET(MAKE_CLOSURE)
+ {
+ v = POP(); /* code object */
+ x = PyFunction_New(v, f->f_globals);
+ Py_DECREF(v);
+ if (x != NULL) {
+ v = POP();
+ if (PyFunction_SetClosure(x, v) != 0) {
+ /* Can't happen unless bytecode is corrupt. */
+ why = WHY_EXCEPTION;
+ }
+ Py_DECREF(v);
+ }
+ if (x != NULL && oparg > 0) {
+ v = PyTuple_New(oparg);
+ if (v == NULL) {
+ Py_DECREF(x);
+ x = NULL;
+ break;
+ }
+ while (--oparg >= 0) {
+ w = POP();
+ PyTuple_SET_ITEM(v, oparg, w);
+ }
+ if (PyFunction_SetDefaults(x, v) != 0) {
+ /* Can't happen unless
+ PyFunction_SetDefaults changes. */
+ why = WHY_EXCEPTION;
+ }
+ Py_DECREF(v);
+ }
+ PUSH(x);
+ break;
+ }
+
+ TARGET(BUILD_SLICE)
+ {
+ if (oparg == 3)
+ w = POP();
+ else
+ w = NULL;
+ v = POP();
+ u = TOP();
+ x = PySlice_New(u, v, w);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_XDECREF(w);
+ SET_TOP(x);
+ if (x != NULL) DISPATCH();
+ break;
+ }
+
+ TARGET(EXTENDED_ARG)
+ {
+ opcode = NEXTOP();
+ oparg = oparg<<16 | NEXTARG();
+ goto dispatch_opcode;
+ }
+
+#if USE_COMPUTED_GOTOS
+ _unknown_opcode:
+#endif
+ default:
+ fprintf(stderr,
+ "XXX lineno: %d, opcode: %d\n",
+ PyFrame_GetLineNumber(f),
+ opcode);
+ PyErr_SetString(PyExc_SystemError, "unknown opcode");
+ why = WHY_EXCEPTION;
+ break;
+
+#ifdef CASE_TOO_BIG
+ }
+#endif
+
+ } /* switch */
+
+ on_error:
+
+ READ_TIMESTAMP(inst1);
+
+ /* Quickly continue if no error occurred */
+
+ if (why == WHY_NOT) {
+ if (err == 0 && x != NULL) {
+#ifdef CHECKEXC
+ /* This check is expensive! */
+ if (PyErr_Occurred())
+ fprintf(stderr,
+ "XXX undetected error\n");
+ else {
+#endif
+ READ_TIMESTAMP(loop1);
+ continue; /* Normal, fast path */
+#ifdef CHECKEXC
+ }
+#endif
+ }
+ why = WHY_EXCEPTION;
+ x = Py_None;
+ err = 0;
+ }
+
+ /* Double-check exception status */
+
+ if (why == WHY_EXCEPTION || why == WHY_RERAISE) {
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_SystemError,
+ "error return without exception set");
+ why = WHY_EXCEPTION;
+ }
+ }
+#ifdef CHECKEXC
+ else {
+ /* This check is expensive! */
+ if (PyErr_Occurred()) {
+ char buf[128];
+ sprintf(buf, "Stack unwind with exception "
+ "set and why=%d", why);
+ Py_FatalError(buf);
+ }
+ }
+#endif
+
+ /* Log traceback info if this is a real exception */
+
+ if (why == WHY_EXCEPTION) {
+ PyTraceBack_Here(f);
+
+ if (tstate->c_tracefunc != NULL)
+ call_exc_trace(tstate->c_tracefunc,
+ tstate->c_traceobj, f);
+ }
+
+ /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
+
+ if (why == WHY_RERAISE)
+ why = WHY_EXCEPTION;
+
+ /* Unwind stacks if a (pseudo) exception occurred */
+
+fast_block_end:
+ while (why != WHY_NOT && f->f_iblock > 0) {
+ /* Peek at the current block. */
+ PyTryBlock *b = &f->f_blockstack[f->f_iblock - 1];
+
+ assert(why != WHY_YIELD);
+ if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) {
+ why = WHY_NOT;
+ JUMPTO(PyInt_AS_LONG(retval));
+ Py_DECREF(retval);
+ break;
+ }
+
+ /* Now we have to pop the block. */
+ f->f_iblock--;
+
+ while (STACK_LEVEL() > b->b_level) {
+ v = POP();
+ Py_XDECREF(v);
+ }
+ if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
+ why = WHY_NOT;
+ JUMPTO(b->b_handler);
+ break;
+ }
+ if (b->b_type == SETUP_FINALLY ||
+ (b->b_type == SETUP_EXCEPT &&
+ why == WHY_EXCEPTION) ||
+ b->b_type == SETUP_WITH) {
+ if (why == WHY_EXCEPTION) {
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ if (val == NULL) {
+ val = Py_None;
+ Py_INCREF(val);
+ }
+ /* Make the raw exception data
+ available to the handler,
+ so a program can emulate the
+ Python main loop. Don't do
+ this for 'finally'. */
+ if (b->b_type == SETUP_EXCEPT ||
+ b->b_type == SETUP_WITH) {
+ PyErr_NormalizeException(
+ &exc, &val, &tb);
+ set_exc_info(tstate,
+ exc, val, tb);
+ }
+ if (tb == NULL) {
+ Py_INCREF(Py_None);
+ PUSH(Py_None);
+ } else
+ PUSH(tb);
+ PUSH(val);
+ PUSH(exc);
+ }
+ else {
+ if (why & (WHY_RETURN | WHY_CONTINUE))
+ PUSH(retval);
+ v = PyInt_FromLong((long)why);
+ PUSH(v);
+ }
+ why = WHY_NOT;
+ JUMPTO(b->b_handler);
+ break;
+ }
+ } /* unwind stack */
+
+ /* End the loop if we still have an error (or return) */
+
+ if (why != WHY_NOT)
+ break;
+ READ_TIMESTAMP(loop1);
+
+ } /* main loop */
+
+ assert(why != WHY_YIELD);
+ /* Pop remaining stack entries. */
+ while (!EMPTY()) {
+ v = POP();
+ Py_XDECREF(v);
+ }
+
+ if (why != WHY_RETURN)
+ retval = NULL;
+
+fast_yield:
+ if (tstate->use_tracing) {
+ if (tstate->c_tracefunc) {
+ if (why == WHY_RETURN || why == WHY_YIELD) {
+ if (call_trace(tstate->c_tracefunc,
+ tstate->c_traceobj, f,
+ PyTrace_RETURN, retval)) {
+ Py_XDECREF(retval);
+ retval = NULL;
+ why = WHY_EXCEPTION;
+ }
+ }
+ else if (why == WHY_EXCEPTION) {
+ call_trace_protected(tstate->c_tracefunc,
+ tstate->c_traceobj, f,
+ PyTrace_RETURN, NULL);
+ }
+ }
+ if (tstate->c_profilefunc) {
+ if (why == WHY_EXCEPTION)
+ call_trace_protected(tstate->c_profilefunc,
+ tstate->c_profileobj, f,
+ PyTrace_RETURN, NULL);
+ else if (call_trace(tstate->c_profilefunc,
+ tstate->c_profileobj, f,
+ PyTrace_RETURN, retval)) {
+ Py_XDECREF(retval);
+ retval = NULL;
+ why = WHY_EXCEPTION;
+ }
+ }
+ }
+
+ if (tstate->frame->f_exc_type != NULL)
+ reset_exc_info(tstate);
+ else {
+ assert(tstate->frame->f_exc_value == NULL);
+ assert(tstate->frame->f_exc_traceback == NULL);
+ }
+
+ /* pop frame */
+exit_eval_frame:
+ Py_LeaveRecursiveCall();
+ tstate->frame = f->f_back;
+
+ return retval;
+}
+
+/* This is gonna seem *real weird*, but if you put some other code between
+ PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust
+ the test in the if statements in Misc/gdbinit (pystack and pystackv). */
+
+PyObject *
+PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
+ PyObject **args, int argcount, PyObject **kws, int kwcount,
+ PyObject **defs, int defcount, PyObject *closure)
+{
+ register PyFrameObject *f;
+ register PyObject *retval = NULL;
+ register PyObject **fastlocals, **freevars;
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *x, *u;
+
+ if (globals == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "PyEval_EvalCodeEx: NULL globals");
+ return NULL;
+ }
+
+ assert(tstate != NULL);
+ assert(globals != NULL);
+ f = PyFrame_New(tstate, co, globals, locals);
+ if (f == NULL)
+ return NULL;
+
+ fastlocals = f->f_localsplus;
+ freevars = f->f_localsplus + co->co_nlocals;
+
+ if (co->co_argcount > 0 ||
+ co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
+ int i;
+ int n = argcount;
+ PyObject *kwdict = NULL;
+ if (co->co_flags & CO_VARKEYWORDS) {
+ kwdict = PyDict_New();
+ if (kwdict == NULL)
+ goto fail;
+ i = co->co_argcount;
+ if (co->co_flags & CO_VARARGS)
+ i++;
+ SETLOCAL(i, kwdict);
+ }
+ if (argcount > co->co_argcount) {
+ if (!(co->co_flags & CO_VARARGS)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes %s %d "
+ "argument%s (%d given)",
+ PyString_AsString(co->co_name),
+ defcount ? "at most" : "exactly",
+ co->co_argcount,
+ co->co_argcount == 1 ? "" : "s",
+ argcount + kwcount);
+ goto fail;
+ }
+ n = co->co_argcount;
+ }
+ for (i = 0; i < n; i++) {
+ x = args[i];
+ Py_INCREF(x);
+ SETLOCAL(i, x);
+ }
+ if (co->co_flags & CO_VARARGS) {
+ u = PyTuple_New(argcount - n);
+ if (u == NULL)
+ goto fail;
+ SETLOCAL(co->co_argcount, u);
+ for (i = n; i < argcount; i++) {
+ x = args[i];
+ Py_INCREF(x);
+ PyTuple_SET_ITEM(u, i-n, x);
+ }
+ }
+ for (i = 0; i < kwcount; i++) {
+ PyObject **co_varnames;
+ PyObject *keyword = kws[2*i];
+ PyObject *value = kws[2*i + 1];
+ int j;
+ if (keyword == NULL || !(PyString_Check(keyword)
+#ifdef Py_USING_UNICODE
+ || PyUnicode_Check(keyword)
+#endif
+ )) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() keywords must be strings",
+ PyString_AsString(co->co_name));
+ goto fail;
+ }
+ /* Speed hack: do raw pointer compares. As names are
+ normally interned this should almost always hit. */
+ co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
+ for (j = 0; j < co->co_argcount; j++) {
+ PyObject *nm = co_varnames[j];
+ if (nm == keyword)
+ goto kw_found;
+ }
+ /* Slow fallback, just in case */
+ for (j = 0; j < co->co_argcount; j++) {
+ PyObject *nm = co_varnames[j];
+ int cmp = PyObject_RichCompareBool(
+ keyword, nm, Py_EQ);
+ if (cmp > 0)
+ goto kw_found;
+ else if (cmp < 0)
+ goto fail;
+ }
+ if (kwdict == NULL) {
+ PyObject *kwd_str = kwd_as_string(keyword);
+ if (kwd_str) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() got an unexpected "
+ "keyword argument '%.400s'",
+ PyString_AsString(co->co_name),
+ PyString_AsString(kwd_str));
+ Py_DECREF(kwd_str);
+ }
+ goto fail;
+ }
+ PyDict_SetItem(kwdict, keyword, value);
+ continue;
+ kw_found:
+ if (GETLOCAL(j) != NULL) {
+ PyObject *kwd_str = kwd_as_string(keyword);
+ if (kwd_str) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() got multiple "
+ "values for keyword "
+ "argument '%.400s'",
+ PyString_AsString(co->co_name),
+ PyString_AsString(kwd_str));
+ Py_DECREF(kwd_str);
+ }
+ goto fail;
+ }
+ Py_INCREF(value);
+ SETLOCAL(j, value);
+ }
+ if (argcount < co->co_argcount) {
+ int m = co->co_argcount - defcount;
+ for (i = argcount; i < m; i++) {
+ if (GETLOCAL(i) == NULL) {
+ int j, given = 0;
+ for (j = 0; j < co->co_argcount; j++)
+ if (GETLOCAL(j))
+ given++;
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes %s %d "
+ "argument%s (%d given)",
+ PyString_AsString(co->co_name),
+ ((co->co_flags & CO_VARARGS) ||
+ defcount) ? "at least"
+ : "exactly",
+ m, m == 1 ? "" : "s", given);
+ goto fail;
+ }
+ }
+ if (n > m)
+ i = n - m;
+ else
+ i = 0;
+ for (; i < defcount; i++) {
+ if (GETLOCAL(m+i) == NULL) {
+ PyObject *def = defs[i];
+ Py_INCREF(def);
+ SETLOCAL(m+i, def);
+ }
+ }
+ }
+ }
+ else if (argcount > 0 || kwcount > 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no arguments (%d given)",
+ PyString_AsString(co->co_name),
+ argcount + kwcount);
+ goto fail;
+ }
+ /* Allocate and initialize storage for cell vars, and copy free
+ vars into frame. This isn't too efficient right now. */
+ if (PyTuple_GET_SIZE(co->co_cellvars)) {
+ int i, j, nargs, found;
+ char *cellname, *argname;
+ PyObject *c;
+
+ nargs = co->co_argcount;
+ if (co->co_flags & CO_VARARGS)
+ nargs++;
+ if (co->co_flags & CO_VARKEYWORDS)
+ nargs++;
+
+ /* Initialize each cell var, taking into account
+ cell vars that are initialized from arguments.
+
+ Should arrange for the compiler to put cellvars
+ that are arguments at the beginning of the cellvars
+ list so that we can march over it more efficiently?
+ */
+ for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
+ cellname = PyString_AS_STRING(
+ PyTuple_GET_ITEM(co->co_cellvars, i));
+ found = 0;
+ for (j = 0; j < nargs; j++) {
+ argname = PyString_AS_STRING(
+ PyTuple_GET_ITEM(co->co_varnames, j));
+ if (strcmp(cellname, argname) == 0) {
+ c = PyCell_New(GETLOCAL(j));
+ if (c == NULL)
+ goto fail;
+ GETLOCAL(co->co_nlocals + i) = c;
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0) {
+ c = PyCell_New(NULL);
+ if (c == NULL)
+ goto fail;
+ SETLOCAL(co->co_nlocals + i, c);
+ }
+ }
+ }
+ if (PyTuple_GET_SIZE(co->co_freevars)) {
+ int i;
+ for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
+ PyObject *o = PyTuple_GET_ITEM(closure, i);
+ Py_INCREF(o);
+ freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
+ }
+ }
+
+ if (co->co_flags & CO_GENERATOR) {
+ /* Don't need to keep the reference to f_back, it will be set
+ * when the generator is resumed. */
+ Py_CLEAR(f->f_back);
+
+ PCALL(PCALL_GENERATOR);
+
+ /* Create a new generator that owns the ready to run frame
+ * and return that as the value. */
+ return PyGen_New(f);
+ }
+
+ retval = PyEval_EvalFrameEx(f,0);
+
+fail: /* Jump here from prelude on failure */
+
+ /* decref'ing the frame can cause __del__ methods to get invoked,
+ which can call back into Python. While we're done with the
+ current Python frame (f), the associated C stack is still in use,
+ so recursion_depth must be boosted for the duration.
+ */
+ assert(tstate != NULL);
+ ++tstate->recursion_depth;
+ Py_DECREF(f);
+ --tstate->recursion_depth;
+ return retval;
+}
+
+
+static PyObject *
+special_lookup(PyObject *o, char *meth, PyObject **cache)
+{
+ PyObject *res;
+ if (PyInstance_Check(o)) {
+ if (!*cache)
+ return PyObject_GetAttrString(o, meth);
+ else
+ return PyObject_GetAttr(o, *cache);
+ }
+ res = _PyObject_LookupSpecial(o, meth, cache);
+ if (res == NULL && !PyErr_Occurred()) {
+ PyErr_SetObject(PyExc_AttributeError, *cache);
+ return NULL;
+ }
+ return res;
+}
+
+
+static PyObject *
+kwd_as_string(PyObject *kwd) {
+#ifdef Py_USING_UNICODE
+ if (PyString_Check(kwd)) {
+#else
+ assert(PyString_Check(kwd));
+#endif
+ Py_INCREF(kwd);
+ return kwd;
+#ifdef Py_USING_UNICODE
+ }
+ return _PyUnicode_AsDefaultEncodedString(kwd, "replace");
+#endif
+}
+
+
+/* Implementation notes for set_exc_info() and reset_exc_info():
+
+- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and
+ 'exc_traceback'. These always travel together.
+
+- tstate->curexc_ZZZ is the "hot" exception that is set by
+ PyErr_SetString(), cleared by PyErr_Clear(), and so on.
+
+- Once an exception is caught by an except clause, it is transferred
+ from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info()
+ can pick it up. This is the primary task of set_exc_info().
+ XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ.
+
+- Now let me explain the complicated dance with frame->f_exc_ZZZ.
+
+ Long ago, when none of this existed, there were just a few globals:
+ one set corresponding to the "hot" exception, and one set
+ corresponding to sys.exc_ZZZ. (Actually, the latter weren't C
+ globals; they were simply stored as sys.exc_ZZZ. For backwards
+ compatibility, they still are!) The problem was that in code like
+ this:
+
+ try:
+ "something that may fail"
+ except "some exception":
+ "do something else first"
+ "print the exception from sys.exc_ZZZ."
+
+ if "do something else first" invoked something that raised and caught
+ an exception, sys.exc_ZZZ were overwritten. That was a frequent
+ cause of subtle bugs. I fixed this by changing the semantics as
+ follows:
+
+ - Within one frame, sys.exc_ZZZ will hold the last exception caught
+ *in that frame*.
+
+ - But initially, and as long as no exception is caught in a given
+ frame, sys.exc_ZZZ will hold the last exception caught in the
+ previous frame (or the frame before that, etc.).
+
+ The first bullet fixed the bug in the above example. The second
+ bullet was for backwards compatibility: it was (and is) common to
+ have a function that is called when an exception is caught, and to
+ have that function access the caught exception via sys.exc_ZZZ.
+ (Example: traceback.print_exc()).
+
+ At the same time I fixed the problem that sys.exc_ZZZ weren't
+ thread-safe, by introducing sys.exc_info() which gets it from tstate;
+ but that's really a separate improvement.
+
+ The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ
+ variables to what they were before the current frame was called. The
+ set_exc_info() function saves them on the frame so that
+ reset_exc_info() can restore them. The invariant is that
+ frame->f_exc_ZZZ is NULL iff the current frame never caught an
+ exception (where "catching" an exception applies only to successful
+ except clauses); and if the current frame ever caught an exception,
+ frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ
+ at the start of the current frame.
+
+*/
+
+static void
+set_exc_info(PyThreadState *tstate,
+ PyObject *type, PyObject *value, PyObject *tb)
+{
+ PyFrameObject *frame = tstate->frame;
+ PyObject *tmp_type, *tmp_value, *tmp_tb;
+
+ assert(type != NULL);
+ assert(frame != NULL);
+ if (frame->f_exc_type == NULL) {
+ assert(frame->f_exc_value == NULL);
+ assert(frame->f_exc_traceback == NULL);
+ /* This frame didn't catch an exception before. */
+ /* Save previous exception of this thread in this frame. */
+ if (tstate->exc_type == NULL) {
+ /* XXX Why is this set to Py_None? */
+ Py_INCREF(Py_None);
+ tstate->exc_type = Py_None;
+ }
+ Py_INCREF(tstate->exc_type);
+ Py_XINCREF(tstate->exc_value);
+ Py_XINCREF(tstate->exc_traceback);
+ frame->f_exc_type = tstate->exc_type;
+ frame->f_exc_value = tstate->exc_value;
+ frame->f_exc_traceback = tstate->exc_traceback;
+ }
+ /* Set new exception for this thread. */
+ tmp_type = tstate->exc_type;
+ tmp_value = tstate->exc_value;
+ tmp_tb = tstate->exc_traceback;
+ Py_INCREF(type);
+ Py_XINCREF(value);
+ Py_XINCREF(tb);
+ tstate->exc_type = type;
+ tstate->exc_value = value;
+ tstate->exc_traceback = tb;
+ Py_XDECREF(tmp_type);
+ Py_XDECREF(tmp_value);
+ Py_XDECREF(tmp_tb);
+ /* For b/w compatibility */
+ PySys_SetObject("exc_type", type);
+ PySys_SetObject("exc_value", value);
+ PySys_SetObject("exc_traceback", tb);
+}
+
+static void
+reset_exc_info(PyThreadState *tstate)
+{
+ PyFrameObject *frame;
+ PyObject *tmp_type, *tmp_value, *tmp_tb;
+
+ /* It's a precondition that the thread state's frame caught an
+ * exception -- verify in a debug build.
+ */
+ assert(tstate != NULL);
+ frame = tstate->frame;
+ assert(frame != NULL);
+ assert(frame->f_exc_type != NULL);
+
+ /* Copy the frame's exception info back to the thread state. */
+ tmp_type = tstate->exc_type;
+ tmp_value = tstate->exc_value;
+ tmp_tb = tstate->exc_traceback;
+ Py_INCREF(frame->f_exc_type);
+ Py_XINCREF(frame->f_exc_value);
+ Py_XINCREF(frame->f_exc_traceback);
+ tstate->exc_type = frame->f_exc_type;
+ tstate->exc_value = frame->f_exc_value;
+ tstate->exc_traceback = frame->f_exc_traceback;
+ Py_XDECREF(tmp_type);
+ Py_XDECREF(tmp_value);
+ Py_XDECREF(tmp_tb);
+
+ /* For b/w compatibility */
+ PySys_SetObject("exc_type", frame->f_exc_type);
+ PySys_SetObject("exc_value", frame->f_exc_value);
+ PySys_SetObject("exc_traceback", frame->f_exc_traceback);
+
+ /* Clear the frame's exception info. */
+ tmp_type = frame->f_exc_type;
+ tmp_value = frame->f_exc_value;
+ tmp_tb = frame->f_exc_traceback;
+ frame->f_exc_type = NULL;
+ frame->f_exc_value = NULL;
+ frame->f_exc_traceback = NULL;
+ Py_DECREF(tmp_type);
+ Py_XDECREF(tmp_value);
+ Py_XDECREF(tmp_tb);
+}
+
+/* Logic for the raise statement (too complicated for inlining).
+ This *consumes* a reference count to each of its arguments. */
+static enum why_code
+do_raise(PyObject *type, PyObject *value, PyObject *tb)
+{
+ if (type == NULL) {
+ /* Reraise */
+ PyThreadState *tstate = PyThreadState_GET();
+ type = tstate->exc_type == NULL ? Py_None : tstate->exc_type;
+ value = tstate->exc_value;
+ tb = tstate->exc_traceback;
+ Py_XINCREF(type);
+ Py_XINCREF(value);
+ Py_XINCREF(tb);
+ }
+
+ /* We support the following forms of raise:
+ raise <class>, <classinstance>
+ raise <class>, <argument tuple>
+ raise <class>, None
+ raise <class>, <argument>
+ raise <classinstance>, None
+ raise <string>, <object>
+ raise <string>, None
+
+ An omitted second argument is the same as None.
+
+ In addition, raise <tuple>, <anything> is the same as
+ raising the tuple's first item (and it better have one!);
+ this rule is applied recursively.
+
+ Finally, an optional third argument can be supplied, which
+ gives the traceback to be substituted (useful when
+ re-raising an exception after examining it). */
+
+ /* First, check the traceback argument, replacing None with
+ NULL. */
+ if (tb == Py_None) {
+ Py_DECREF(tb);
+ tb = NULL;
+ }
+ else if (tb != NULL && !PyTraceBack_Check(tb)) {
+ PyErr_SetString(PyExc_TypeError,
+ "raise: arg 3 must be a traceback or None");
+ goto raise_error;
+ }
+
+ /* Next, replace a missing value with None */
+ if (value == NULL) {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+
+ /* Next, repeatedly, replace a tuple exception with its first item */
+ while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
+ PyObject *tmp = type;
+ type = PyTuple_GET_ITEM(type, 0);
+ Py_INCREF(type);
+ Py_DECREF(tmp);
+ }
+
+ if (PyExceptionClass_Check(type)) {
+ PyErr_NormalizeException(&type, &value, &tb);
+ if (!PyExceptionInstance_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "calling %s() should have returned an instance of "
+ "BaseException, not '%s'",
+ ((PyTypeObject *)type)->tp_name,
+ Py_TYPE(value)->tp_name);
+ goto raise_error;
+ }
+ }
+ else if (PyExceptionInstance_Check(type)) {
+ /* Raising an instance. The value should be a dummy. */
+ if (value != Py_None) {
+ PyErr_SetString(PyExc_TypeError,
+ "instance exception may not have a separate value");
+ goto raise_error;
+ }
+ else {
+ /* Normalize to raise <class>, <instance> */
+ Py_DECREF(value);
+ value = type;
+ type = PyExceptionInstance_Class(type);
+ Py_INCREF(type);
+ }
+ }
+ else {
+ /* Not something you can raise. You get an exception
+ anyway, just not what you specified :-) */
+ PyErr_Format(PyExc_TypeError,
+ "exceptions must be old-style classes or "
+ "derived from BaseException, not %s",
+ type->ob_type->tp_name);
+ goto raise_error;
+ }
+
+ assert(PyExceptionClass_Check(type));
+ if (Py_Py3kWarningFlag && PyClass_Check(type)) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "exceptions must derive from BaseException "
+ "in 3.x", 1) < 0)
+ goto raise_error;
+ }
+
+ PyErr_Restore(type, value, tb);
+ if (tb == NULL)
+ return WHY_EXCEPTION;
+ else
+ return WHY_RERAISE;
+ raise_error:
+ Py_XDECREF(value);
+ Py_XDECREF(type);
+ Py_XDECREF(tb);
+ return WHY_EXCEPTION;
+}
+
+/* Iterate v argcnt times and store the results on the stack (via decreasing
+ sp). Return 1 for success, 0 if error. */
+
+static int
+unpack_iterable(PyObject *v, int argcnt, PyObject **sp)
+{
+ int i = 0;
+ PyObject *it; /* iter(v) */
+ PyObject *w;
+
+ assert(v != NULL);
+
+ it = PyObject_GetIter(v);
+ if (it == NULL)
+ goto Error;
+
+ for (; i < argcnt; i++) {
+ w = PyIter_Next(it);
+ if (w == NULL) {
+ /* Iterator done, via error or exhaustion. */
+ if (!PyErr_Occurred()) {
+ PyErr_Format(PyExc_ValueError,
+ "need more than %d value%s to unpack",
+ i, i == 1 ? "" : "s");
+ }
+ goto Error;
+ }
+ *--sp = w;
+ }
+
+ /* We better have exhausted the iterator now. */
+ w = PyIter_Next(it);
+ if (w == NULL) {
+ if (PyErr_Occurred())
+ goto Error;
+ Py_DECREF(it);
+ return 1;
+ }
+ Py_DECREF(w);
+ PyErr_SetString(PyExc_ValueError, "too many values to unpack");
+ /* fall through */
+Error:
+ for (; i > 0; i--, sp++)
+ Py_DECREF(*sp);
+ Py_XDECREF(it);
+ return 0;
+}
+
+
+#ifdef LLTRACE
+static int
+prtrace(PyObject *v, char *str)
+{
+ printf("%s ", str);
+ if (PyObject_Print(v, stdout, 0) != 0)
+ PyErr_Clear(); /* Don't know what else to do */
+ printf("\n");
+ return 1;
+}
+#endif
+
+static void
+call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f)
+{
+ PyObject *type, *value, *traceback, *arg;
+ int err;
+ PyErr_Fetch(&type, &value, &traceback);
+ if (value == NULL) {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+ arg = PyTuple_Pack(3, type, value, traceback);
+ if (arg == NULL) {
+ PyErr_Restore(type, value, traceback);
+ return;
+ }
+ err = call_trace(func, self, f, PyTrace_EXCEPTION, arg);
+ Py_DECREF(arg);
+ if (err == 0)
+ PyErr_Restore(type, value, traceback);
+ else {
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(traceback);
+ }
+}
+
+static int
+call_trace_protected(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ PyObject *type, *value, *traceback;
+ int err;
+ PyErr_Fetch(&type, &value, &traceback);
+ err = call_trace(func, obj, frame, what, arg);
+ if (err == 0)
+ {
+ PyErr_Restore(type, value, traceback);
+ return 0;
+ }
+ else {
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(traceback);
+ return -1;
+ }
+}
+
+static int
+call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ register PyThreadState *tstate = frame->f_tstate;
+ int result;
+ if (tstate->tracing)
+ return 0;
+ tstate->tracing++;
+ tstate->use_tracing = 0;
+ result = func(obj, frame, what, arg);
+ tstate->use_tracing = ((tstate->c_tracefunc != NULL)
+ || (tstate->c_profilefunc != NULL));
+ tstate->tracing--;
+ return result;
+}
+
+PyObject *
+_PyEval_CallTracing(PyObject *func, PyObject *args)
+{
+ PyFrameObject *frame = PyEval_GetFrame();
+ PyThreadState *tstate = frame->f_tstate;
+ int save_tracing = tstate->tracing;
+ int save_use_tracing = tstate->use_tracing;
+ PyObject *result;
+
+ tstate->tracing = 0;
+ tstate->use_tracing = ((tstate->c_tracefunc != NULL)
+ || (tstate->c_profilefunc != NULL));
+ result = PyObject_Call(func, args, NULL);
+ tstate->tracing = save_tracing;
+ tstate->use_tracing = save_use_tracing;
+ return result;
+}
+
+/* See Objects/lnotab_notes.txt for a description of how tracing works. */
+static int
+maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
+ PyFrameObject *frame, int *instr_lb, int *instr_ub,
+ int *instr_prev)
+{
+ int result = 0;
+ int line = frame->f_lineno;
+
+ /* If the last instruction executed isn't in the current
+ instruction window, reset the window.
+ */
+ if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
+ PyAddrPair bounds;
+ line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
+ &bounds);
+ *instr_lb = bounds.ap_lower;
+ *instr_ub = bounds.ap_upper;
+ }
+ /* If the last instruction falls at the start of a line or if
+ it represents a jump backwards, update the frame's line
+ number and call the trace function. */
+ if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
+ frame->f_lineno = line;
+ result = call_trace(func, obj, frame, PyTrace_LINE, Py_None);
+ }
+ *instr_prev = frame->f_lasti;
+ return result;
+}
+
+void
+PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *temp = tstate->c_profileobj;
+ Py_XINCREF(arg);
+ tstate->c_profilefunc = NULL;
+ tstate->c_profileobj = NULL;
+ /* Must make sure that tracing is not ignored if 'temp' is freed */
+ tstate->use_tracing = tstate->c_tracefunc != NULL;
+ Py_XDECREF(temp);
+ tstate->c_profilefunc = func;
+ tstate->c_profileobj = arg;
+ /* Flag that tracing or profiling is turned on */
+ tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
+}
+
+void
+PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *temp = tstate->c_traceobj;
+ _Py_TracingPossible += (func != NULL) - (tstate->c_tracefunc != NULL);
+ Py_XINCREF(arg);
+ tstate->c_tracefunc = NULL;
+ tstate->c_traceobj = NULL;
+ /* Must make sure that profiling is not ignored if 'temp' is freed */
+ tstate->use_tracing = tstate->c_profilefunc != NULL;
+ Py_XDECREF(temp);
+ tstate->c_tracefunc = func;
+ tstate->c_traceobj = arg;
+ /* Flag that tracing or profiling is turned on */
+ tstate->use_tracing = ((func != NULL)
+ || (tstate->c_profilefunc != NULL));
+}
+
+PyObject *
+PyEval_GetBuiltins(void)
+{
+ PyFrameObject *current_frame = PyEval_GetFrame();
+ if (current_frame == NULL)
+ return PyThreadState_GET()->interp->builtins;
+ else
+ return current_frame->f_builtins;
+}
+
+PyObject *
+PyEval_GetLocals(void)
+{
+ PyFrameObject *current_frame = PyEval_GetFrame();
+ if (current_frame == NULL)
+ return NULL;
+ PyFrame_FastToLocals(current_frame);
+ return current_frame->f_locals;
+}
+
+PyObject *
+PyEval_GetGlobals(void)
+{
+ PyFrameObject *current_frame = PyEval_GetFrame();
+ if (current_frame == NULL)
+ return NULL;
+ else
+ return current_frame->f_globals;
+}
+
+PyFrameObject *
+PyEval_GetFrame(void)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ return _PyThreadState_GetFrame(tstate);
+}
+
+int
+PyEval_GetRestricted(void)
+{
+ PyFrameObject *current_frame = PyEval_GetFrame();
+ return current_frame == NULL ? 0 : PyFrame_IsRestricted(current_frame);
+}
+
+int
+PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
+{
+ PyFrameObject *current_frame = PyEval_GetFrame();
+ int result = cf->cf_flags != 0;
+
+ if (current_frame != NULL) {
+ const int codeflags = current_frame->f_code->co_flags;
+ const int compilerflags = codeflags & PyCF_MASK;
+ if (compilerflags) {
+ result = 1;
+ cf->cf_flags |= compilerflags;
+ }
+#if 0 /* future keyword */
+ if (codeflags & CO_GENERATOR_ALLOWED) {
+ result = 1;
+ cf->cf_flags |= CO_GENERATOR_ALLOWED;
+ }
+#endif
+ }
+ return result;
+}
+
+int
+Py_FlushLine(void)
+{
+ PyObject *f = PySys_GetObject("stdout");
+ if (f == NULL)
+ return 0;
+ if (!PyFile_SoftSpace(f, 0))
+ return 0;
+ return PyFile_WriteString("\n", f);
+}
+
+
+/* External interface to call any callable object.
+ The arg must be a tuple or NULL. The kw must be a dict or NULL. */
+
+PyObject *
+PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
+{
+ PyObject *result;
+
+ if (arg == NULL) {
+ arg = PyTuple_New(0);
+ if (arg == NULL)
+ return NULL;
+ }
+ else if (!PyTuple_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument list must be a tuple");
+ return NULL;
+ }
+ else
+ Py_INCREF(arg);
+
+ if (kw != NULL && !PyDict_Check(kw)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keyword list must be a dictionary");
+ Py_DECREF(arg);
+ return NULL;
+ }
+
+ result = PyObject_Call(func, arg, kw);
+ Py_DECREF(arg);
+ return result;
+}
+
+const char *
+PyEval_GetFuncName(PyObject *func)
+{
+ if (PyMethod_Check(func))
+ return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func));
+ else if (PyFunction_Check(func))
+ return PyString_AsString(((PyFunctionObject*)func)->func_name);
+ else if (PyCFunction_Check(func))
+ return ((PyCFunctionObject*)func)->m_ml->ml_name;
+ else if (PyClass_Check(func))
+ return PyString_AsString(((PyClassObject*)func)->cl_name);
+ else if (PyInstance_Check(func)) {
+ return PyString_AsString(
+ ((PyInstanceObject*)func)->in_class->cl_name);
+ } else {
+ return func->ob_type->tp_name;
+ }
+}
+
+const char *
+PyEval_GetFuncDesc(PyObject *func)
+{
+ if (PyMethod_Check(func))
+ return "()";
+ else if (PyFunction_Check(func))
+ return "()";
+ else if (PyCFunction_Check(func))
+ return "()";
+ else if (PyClass_Check(func))
+ return " constructor";
+ else if (PyInstance_Check(func)) {
+ return " instance";
+ } else {
+ return " object";
+ }
+}
+
+static void
+err_args(PyObject *func, int flags, int nargs)
+{
+ if (flags & METH_NOARGS)
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no arguments (%d given)",
+ ((PyCFunctionObject *)func)->m_ml->ml_name,
+ nargs);
+ else
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes exactly one argument (%d given)",
+ ((PyCFunctionObject *)func)->m_ml->ml_name,
+ nargs);
+}
+
+#define C_TRACE(x, call) \
+if (tstate->use_tracing && tstate->c_profilefunc) { \
+ if (call_trace(tstate->c_profilefunc, \
+ tstate->c_profileobj, \
+ tstate->frame, PyTrace_C_CALL, \
+ func)) { \
+ x = NULL; \
+ } \
+ else { \
+ x = call; \
+ if (tstate->c_profilefunc != NULL) { \
+ if (x == NULL) { \
+ call_trace_protected(tstate->c_profilefunc, \
+ tstate->c_profileobj, \
+ tstate->frame, PyTrace_C_EXCEPTION, \
+ func); \
+ /* XXX should pass (type, value, tb) */ \
+ } else { \
+ if (call_trace(tstate->c_profilefunc, \
+ tstate->c_profileobj, \
+ tstate->frame, PyTrace_C_RETURN, \
+ func)) { \
+ Py_DECREF(x); \
+ x = NULL; \
+ } \
+ } \
+ } \
+ } \
+} else { \
+ x = call; \
+ }
+
+static PyObject *
+call_function(PyObject ***pp_stack, int oparg
+#ifdef WITH_TSC
+ , uint64* pintr0, uint64* pintr1
+#endif
+ )
+{
+ int na = oparg & 0xff;
+ int nk = (oparg>>8) & 0xff;
+ int n = na + 2 * nk;
+ PyObject **pfunc = (*pp_stack) - n - 1;
+ PyObject *func = *pfunc;
+ PyObject *x, *w;
+
+ /* Always dispatch PyCFunction first, because these are
+ presumed to be the most frequent callable object.
+ */
+ if (PyCFunction_Check(func) && nk == 0) {
+ int flags = PyCFunction_GET_FLAGS(func);
+ PyThreadState *tstate = PyThreadState_GET();
+
+ PCALL(PCALL_CFUNCTION);
+ if (flags & (METH_NOARGS | METH_O)) {
+ PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+ PyObject *self = PyCFunction_GET_SELF(func);
+ if (flags & METH_NOARGS && na == 0) {
+ C_TRACE(x, (*meth)(self,NULL));
+ }
+ else if (flags & METH_O && na == 1) {
+ PyObject *arg = EXT_POP(*pp_stack);
+ C_TRACE(x, (*meth)(self,arg));
+ Py_DECREF(arg);
+ }
+ else {
+ err_args(func, flags, na);
+ x = NULL;
+ }
+ }
+ else {
+ PyObject *callargs;
+ callargs = load_args(pp_stack, na);
+ READ_TIMESTAMP(*pintr0);
+ C_TRACE(x, PyCFunction_Call(func,callargs,NULL));
+ READ_TIMESTAMP(*pintr1);
+ Py_XDECREF(callargs);
+ }
+ } else {
+ if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
+ /* optimize access to bound methods */
+ PyObject *self = PyMethod_GET_SELF(func);
+ PCALL(PCALL_METHOD);
+ PCALL(PCALL_BOUND_METHOD);
+ Py_INCREF(self);
+ func = PyMethod_GET_FUNCTION(func);
+ Py_INCREF(func);
+ Py_SETREF(*pfunc, self);
+ na++;
+ n++;
+ } else
+ Py_INCREF(func);
+ READ_TIMESTAMP(*pintr0);
+ if (PyFunction_Check(func))
+ x = fast_function(func, pp_stack, n, na, nk);
+ else
+ x = do_call(func, pp_stack, na, nk);
+ READ_TIMESTAMP(*pintr1);
+ Py_DECREF(func);
+ }
+
+ /* Clear the stack of the function object. Also removes
+ the arguments in case they weren't consumed already
+ (fast_function() and err_args() leave them on the stack).
+ */
+ while ((*pp_stack) > pfunc) {
+ w = EXT_POP(*pp_stack);
+ Py_DECREF(w);
+ PCALL(PCALL_POP);
+ }
+ return x;
+}
+
+/* The fast_function() function optimize calls for which no argument
+ tuple is necessary; the objects are passed directly from the stack.
+ For the simplest case -- a function that takes only positional
+ arguments and is called with only positional arguments -- it
+ inlines the most primitive frame setup code from
+ PyEval_EvalCodeEx(), which vastly reduces the checks that must be
+ done before evaluating the frame.
+*/
+
+static PyObject *
+fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
+{
+ PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
+ PyObject *globals = PyFunction_GET_GLOBALS(func);
+ PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
+ PyObject **d = NULL;
+ int nd = 0;
+
+ PCALL(PCALL_FUNCTION);
+ PCALL(PCALL_FAST_FUNCTION);
+ if (argdefs == NULL && co->co_argcount == n && nk==0 &&
+ co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {
+ PyFrameObject *f;
+ PyObject *retval = NULL;
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject **fastlocals, **stack;
+ int i;
+
+ PCALL(PCALL_FASTER_FUNCTION);
+ assert(globals != NULL);
+ /* XXX Perhaps we should create a specialized
+ PyFrame_New() that doesn't take locals, but does
+ take builtins without sanity checking them.
+ */
+ assert(tstate != NULL);
+ f = PyFrame_New(tstate, co, globals, NULL);
+ if (f == NULL)
+ return NULL;
+
+ fastlocals = f->f_localsplus;
+ stack = (*pp_stack) - n;
+
+ for (i = 0; i < n; i++) {
+ Py_INCREF(*stack);
+ fastlocals[i] = *stack++;
+ }
+ retval = PyEval_EvalFrameEx(f,0);
+ ++tstate->recursion_depth;
+ Py_DECREF(f);
+ --tstate->recursion_depth;
+ return retval;
+ }
+ if (argdefs != NULL) {
+ d = &PyTuple_GET_ITEM(argdefs, 0);
+ nd = Py_SIZE(argdefs);
+ }
+ return PyEval_EvalCodeEx(co, globals,
+ (PyObject *)NULL, (*pp_stack)-n, na,
+ (*pp_stack)-2*nk, nk, d, nd,
+ PyFunction_GET_CLOSURE(func));
+}
+
+static PyObject *
+update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
+ PyObject *func)
+{
+ PyObject *kwdict = NULL;
+ if (orig_kwdict == NULL)
+ kwdict = PyDict_New();
+ else {
+ kwdict = PyDict_Copy(orig_kwdict);
+ Py_DECREF(orig_kwdict);
+ }
+ if (kwdict == NULL)
+ return NULL;
+ while (--nk >= 0) {
+ int err;
+ PyObject *value = EXT_POP(*pp_stack);
+ PyObject *key = EXT_POP(*pp_stack);
+ if (PyDict_GetItem(kwdict, key) != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s got multiple values "
+ "for keyword argument '%.200s'",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ PyString_AsString(key));
+ Py_DECREF(key);
+ Py_DECREF(value);
+ Py_DECREF(kwdict);
+ return NULL;
+ }
+ err = PyDict_SetItem(kwdict, key, value);
+ Py_DECREF(key);
+ Py_DECREF(value);
+ if (err) {
+ Py_DECREF(kwdict);
+ return NULL;
+ }
+ }
+ return kwdict;
+}
+
+static PyObject *
+update_star_args(int nstack, int nstar, PyObject *stararg,
+ PyObject ***pp_stack)
+{
+ PyObject *callargs, *w;
+
+ callargs = PyTuple_New(nstack + nstar);
+ if (callargs == NULL) {
+ return NULL;
+ }
+ if (nstar) {
+ int i;
+ for (i = 0; i < nstar; i++) {
+ PyObject *a = PyTuple_GET_ITEM(stararg, i);
+ Py_INCREF(a);
+ PyTuple_SET_ITEM(callargs, nstack + i, a);
+ }
+ }
+ while (--nstack >= 0) {
+ w = EXT_POP(*pp_stack);
+ PyTuple_SET_ITEM(callargs, nstack, w);
+ }
+ return callargs;
+}
+
+static PyObject *
+load_args(PyObject ***pp_stack, int na)
+{
+ PyObject *args = PyTuple_New(na);
+ PyObject *w;
+
+ if (args == NULL)
+ return NULL;
+ while (--na >= 0) {
+ w = EXT_POP(*pp_stack);
+ PyTuple_SET_ITEM(args, na, w);
+ }
+ return args;
+}
+
+static PyObject *
+do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
+{
+ PyObject *callargs = NULL;
+ PyObject *kwdict = NULL;
+ PyObject *result = NULL;
+
+ if (nk > 0) {
+ kwdict = update_keyword_args(NULL, nk, pp_stack, func);
+ if (kwdict == NULL)
+ goto call_fail;
+ }
+ callargs = load_args(pp_stack, na);
+ if (callargs == NULL)
+ goto call_fail;
+#ifdef CALL_PROFILE
+ /* At this point, we have to look at the type of func to
+ update the call stats properly. Do it here so as to avoid
+ exposing the call stats machinery outside ceval.c
+ */
+ if (PyFunction_Check(func))
+ PCALL(PCALL_FUNCTION);
+ else if (PyMethod_Check(func))
+ PCALL(PCALL_METHOD);
+ else if (PyType_Check(func))
+ PCALL(PCALL_TYPE);
+ else if (PyCFunction_Check(func))
+ PCALL(PCALL_CFUNCTION);
+ else
+ PCALL(PCALL_OTHER);
+#endif
+ if (PyCFunction_Check(func)) {
+ PyThreadState *tstate = PyThreadState_GET();
+ C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ }
+ else
+ result = PyObject_Call(func, callargs, kwdict);
+ call_fail:
+ Py_XDECREF(callargs);
+ Py_XDECREF(kwdict);
+ return result;
+}
+
+static PyObject *
+ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
+{
+ int nstar = 0;
+ PyObject *callargs = NULL;
+ PyObject *stararg = NULL;
+ PyObject *kwdict = NULL;
+ PyObject *result = NULL;
+
+ if (flags & CALL_FLAG_KW) {
+ kwdict = EXT_POP(*pp_stack);
+ if (!PyDict_Check(kwdict)) {
+ PyObject *d;
+ d = PyDict_New();
+ if (d == NULL)
+ goto ext_call_fail;
+ if (PyDict_Update(d, kwdict) != 0) {
+ Py_DECREF(d);
+ /* PyDict_Update raises attribute
+ * error (percolated from an attempt
+ * to get 'keys' attribute) instead of
+ * a type error if its second argument
+ * is not a mapping.
+ */
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after ** "
+ "must be a mapping, not %.200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ kwdict->ob_type->tp_name);
+ }
+ goto ext_call_fail;
+ }
+ Py_DECREF(kwdict);
+ kwdict = d;
+ }
+ }
+ if (flags & CALL_FLAG_VAR) {
+ stararg = EXT_POP(*pp_stack);
+ if (!PyTuple_Check(stararg)) {
+ PyObject *t = NULL;
+ t = PySequence_Tuple(stararg);
+ if (t == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError) &&
+ /* Don't mask TypeError raised from a generator */
+ !PyGen_Check(stararg)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after * "
+ "must be an iterable, not %200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ stararg->ob_type->tp_name);
+ }
+ goto ext_call_fail;
+ }
+ Py_DECREF(stararg);
+ stararg = t;
+ }
+ nstar = PyTuple_GET_SIZE(stararg);
+ }
+ if (nk > 0) {
+ kwdict = update_keyword_args(kwdict, nk, pp_stack, func);
+ if (kwdict == NULL)
+ goto ext_call_fail;
+ }
+ callargs = update_star_args(na, nstar, stararg, pp_stack);
+ if (callargs == NULL)
+ goto ext_call_fail;
+#ifdef CALL_PROFILE
+ /* At this point, we have to look at the type of func to
+ update the call stats properly. Do it here so as to avoid
+ exposing the call stats machinery outside ceval.c
+ */
+ if (PyFunction_Check(func))
+ PCALL(PCALL_FUNCTION);
+ else if (PyMethod_Check(func))
+ PCALL(PCALL_METHOD);
+ else if (PyType_Check(func))
+ PCALL(PCALL_TYPE);
+ else if (PyCFunction_Check(func))
+ PCALL(PCALL_CFUNCTION);
+ else
+ PCALL(PCALL_OTHER);
+#endif
+ if (PyCFunction_Check(func)) {
+ PyThreadState *tstate = PyThreadState_GET();
+ C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ }
+ else
+ result = PyObject_Call(func, callargs, kwdict);
+ext_call_fail:
+ Py_XDECREF(callargs);
+ Py_XDECREF(kwdict);
+ Py_XDECREF(stararg);
+ return result;
+}
+
+/* Extract a slice index from a PyInt or PyLong or an object with the
+ nb_index slot defined, and store in *pi.
+ Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
+ and silently boost values less than PY_SSIZE_T_MIN to PY_SSIZE_T_MIN.
+ Return 0 on error, 1 on success.
+*/
+/* Note: If v is NULL, return success without storing into *pi. This
+ is because_PyEval_SliceIndex() is called by apply_slice(), which can be
+ called by the SLICE opcode with v and/or w equal to NULL.
+*/
+int
+_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
+{
+ if (v != NULL && v != Py_None) {
+ Py_ssize_t x;
+ if (PyInt_Check(v)) {
+ /* XXX(nnorwitz): I think PyInt_AS_LONG is correct,
+ however, it looks like it should be AsSsize_t.
+ There should be a comment here explaining why.
+ */
+ x = PyInt_AS_LONG(v);
+ }
+ else if (PyIndex_Check(v)) {
+ x = PyNumber_AsSsize_t(v, NULL);
+ if (x == -1 && PyErr_Occurred())
+ return 0;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "slice indices must be integers or "
+ "None or have an __index__ method");
+ return 0;
+ }
+ *pi = x;
+ }
+ return 1;
+}
+
+int
+_PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
+{
+ Py_ssize_t x;
+ if (PyIndex_Check(v)) {
+ x = PyNumber_AsSsize_t(v, NULL);
+ if (x == -1 && PyErr_Occurred())
+ return 0;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "slice indices must be integers or "
+ "have an __index__ method");
+ return 0;
+ }
+ *pi = x;
+ return 1;
+}
+
+
+#undef ISINDEX
+#define ISINDEX(x) ((x) == NULL || _PyAnyInt_Check(x) || PyIndex_Check(x))
+
+static PyObject *
+apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */
+{
+ PyTypeObject *tp = u->ob_type;
+ PySequenceMethods *sq = tp->tp_as_sequence;
+
+ if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) {
+ Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX;
+ if (!_PyEval_SliceIndex(v, &ilow))
+ return NULL;
+ if (!_PyEval_SliceIndex(w, &ihigh))
+ return NULL;
+ return PySequence_GetSlice(u, ilow, ihigh);
+ }
+ else {
+ PyObject *slice = PySlice_New(v, w, NULL);
+ if (slice != NULL) {
+ PyObject *res = PyObject_GetItem(u, slice);
+ Py_DECREF(slice);
+ return res;
+ }
+ else
+ return NULL;
+ }
+}
+
+static int
+assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x)
+ /* u[v:w] = x */
+{
+ PyTypeObject *tp = u->ob_type;
+ PySequenceMethods *sq = tp->tp_as_sequence;
+
+ if (sq && sq->sq_ass_slice && ISINDEX(v) && ISINDEX(w)) {
+ Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX;
+ if (!_PyEval_SliceIndex(v, &ilow))
+ return -1;
+ if (!_PyEval_SliceIndex(w, &ihigh))
+ return -1;
+ if (x == NULL)
+ return PySequence_DelSlice(u, ilow, ihigh);
+ else
+ return PySequence_SetSlice(u, ilow, ihigh, x);
+ }
+ else {
+ PyObject *slice = PySlice_New(v, w, NULL);
+ if (slice != NULL) {
+ int res;
+ if (x != NULL)
+ res = PyObject_SetItem(u, slice, x);
+ else
+ res = PyObject_DelItem(u, slice);
+ Py_DECREF(slice);
+ return res;
+ }
+ else
+ return -1;
+ }
+}
+
+#define Py3kExceptionClass_Check(x) \
+ (PyType_Check((x)) && \
+ PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))
+
+#define CANNOT_CATCH_MSG "catching classes that don't inherit from " \
+ "BaseException is not allowed in 3.x"
+
+static PyObject *
+cmp_outcome(int op, register PyObject *v, register PyObject *w)
+{
+ int res = 0;
+ switch (op) {
+ case PyCmp_IS:
+ res = (v == w);
+ break;
+ case PyCmp_IS_NOT:
+ res = (v != w);
+ break;
+ case PyCmp_IN:
+ res = PySequence_Contains(w, v);
+ if (res < 0)
+ return NULL;
+ break;
+ case PyCmp_NOT_IN:
+ res = PySequence_Contains(w, v);
+ if (res < 0)
+ return NULL;
+ res = !res;
+ break;
+ case PyCmp_EXC_MATCH:
+ if (PyTuple_Check(w)) {
+ Py_ssize_t i, length;
+ length = PyTuple_Size(w);
+ for (i = 0; i < length; i += 1) {
+ PyObject *exc = PyTuple_GET_ITEM(w, i);
+ if (PyString_Check(exc)) {
+ int ret_val;
+ ret_val = PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ "catching of string "
+ "exceptions is deprecated", 1);
+ if (ret_val < 0)
+ return NULL;
+ }
+ else if (Py_Py3kWarningFlag &&
+ !PyTuple_Check(exc) &&
+ !Py3kExceptionClass_Check(exc))
+ {
+ int ret_val;
+ ret_val = PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ CANNOT_CATCH_MSG, 1);
+ if (ret_val < 0)
+ return NULL;
+ }
+ }
+ }
+ else {
+ if (PyString_Check(w)) {
+ int ret_val;
+ ret_val = PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ "catching of string "
+ "exceptions is deprecated", 1);
+ if (ret_val < 0)
+ return NULL;
+ }
+ else if (Py_Py3kWarningFlag &&
+ !PyTuple_Check(w) &&
+ !Py3kExceptionClass_Check(w))
+ {
+ int ret_val;
+ ret_val = PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ CANNOT_CATCH_MSG, 1);
+ if (ret_val < 0)
+ return NULL;
+ }
+ }
+ res = PyErr_GivenExceptionMatches(v, w);
+ break;
+ default:
+ return PyObject_RichCompare(v, w, op);
+ }
+ v = res ? Py_True : Py_False;
+ Py_INCREF(v);
+ return v;
+}
+
+static PyObject *
+import_from(PyObject *v, PyObject *name)
+{
+ PyObject *x;
+
+ x = PyObject_GetAttr(v, name);
+ if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Format(PyExc_ImportError,
+ "cannot import name %.230s",
+ PyString_AsString(name));
+ }
+ return x;
+}
+
+static int
+import_all_from(PyObject *locals, PyObject *v)
+{
+ PyObject *all = PyObject_GetAttrString(v, "__all__");
+ PyObject *dict, *name, *value;
+ int skip_leading_underscores = 0;
+ int pos, err;
+
+ if (all == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ return -1; /* Unexpected error */
+ PyErr_Clear();
+ dict = PyObject_GetAttrString(v, "__dict__");
+ if (dict == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ return -1;
+ PyErr_SetString(PyExc_ImportError,
+ "from-import-* object has no __dict__ and no __all__");
+ return -1;
+ }
+ all = PyMapping_Keys(dict);
+ Py_DECREF(dict);
+ if (all == NULL)
+ return -1;
+ skip_leading_underscores = 1;
+ }
+
+ for (pos = 0, err = 0; ; pos++) {
+ name = PySequence_GetItem(all, pos);
+ if (name == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_IndexError))
+ err = -1;
+ else
+ PyErr_Clear();
+ break;
+ }
+ if (skip_leading_underscores &&
+ PyString_Check(name) &&
+ PyString_AS_STRING(name)[0] == '_')
+ {
+ Py_DECREF(name);
+ continue;
+ }
+ value = PyObject_GetAttr(v, name);
+ if (value == NULL)
+ err = -1;
+ else if (PyDict_CheckExact(locals))
+ err = PyDict_SetItem(locals, name, value);
+ else
+ err = PyObject_SetItem(locals, name, value);
+ Py_DECREF(name);
+ Py_XDECREF(value);
+ if (err != 0)
+ break;
+ }
+ Py_DECREF(all);
+ return err;
+}
+
+static PyObject *
+build_class(PyObject *methods, PyObject *bases, PyObject *name)
+{
+ PyObject *metaclass = NULL, *result, *base;
+
+ if (PyDict_Check(methods))
+ metaclass = PyDict_GetItemString(methods, "__metaclass__");
+ if (metaclass != NULL)
+ Py_INCREF(metaclass);
+ else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+ base = PyTuple_GET_ITEM(bases, 0);
+ metaclass = PyObject_GetAttrString(base, "__class__");
+ if (metaclass == NULL) {
+ PyErr_Clear();
+ metaclass = (PyObject *)base->ob_type;
+ Py_INCREF(metaclass);
+ }
+ }
+ else {
+ PyObject *g = PyEval_GetGlobals();
+ if (g != NULL && PyDict_Check(g))
+ metaclass = PyDict_GetItemString(g, "__metaclass__");
+ if (metaclass == NULL)
+ metaclass = (PyObject *) &PyClass_Type;
+ Py_INCREF(metaclass);
+ }
+ result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods,
+ NULL);
+ Py_DECREF(metaclass);
+ if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
+ /* A type error here likely means that the user passed
+ in a base that was not a class (such the random module
+ instead of the random.random type). Help them out with
+ by augmenting the error message with more information.*/
+
+ PyObject *ptype, *pvalue, *ptraceback;
+
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+ if (PyString_Check(pvalue)) {
+ PyObject *newmsg;
+ newmsg = PyString_FromFormat(
+ "Error when calling the metaclass bases\n"
+ " %s",
+ PyString_AS_STRING(pvalue));
+ if (newmsg != NULL) {
+ Py_DECREF(pvalue);
+ pvalue = newmsg;
+ }
+ }
+ PyErr_Restore(ptype, pvalue, ptraceback);
+ }
+ return result;
+}
+
+static int
+exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
+ PyObject *locals)
+{
+ int n;
+ PyObject *v;
+ int plain = 0;
+
+ if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None &&
+ ((n = PyTuple_Size(prog)) == 2 || n == 3)) {
+ /* Backward compatibility hack */
+ globals = PyTuple_GetItem(prog, 1);
+ if (n == 3)
+ locals = PyTuple_GetItem(prog, 2);
+ prog = PyTuple_GetItem(prog, 0);
+ }
+ if (globals == Py_None) {
+ globals = PyEval_GetGlobals();
+ if (locals == Py_None) {
+ locals = PyEval_GetLocals();
+ plain = 1;
+ }
+ if (!globals || !locals) {
+ PyErr_SetString(PyExc_SystemError,
+ "globals and locals cannot be NULL");
+ return -1;
+ }
+ }
+ else if (locals == Py_None)
+ locals = globals;
+ if (!PyString_Check(prog) &&
+#ifdef Py_USING_UNICODE
+ !PyUnicode_Check(prog) &&
+#endif
+ !PyCode_Check(prog) &&
+ !PyFile_Check(prog)) {
+ PyErr_SetString(PyExc_TypeError,
+ "exec: arg 1 must be a string, file, or code object");
+ return -1;
+ }
+ if (!PyDict_Check(globals)) {
+ PyErr_SetString(PyExc_TypeError,
+ "exec: arg 2 must be a dictionary or None");
+ return -1;
+ }
+ if (!PyMapping_Check(locals)) {
+ PyErr_SetString(PyExc_TypeError,
+ "exec: arg 3 must be a mapping or None");
+ return -1;
+ }
+ if (PyDict_GetItemString(globals, "__builtins__") == NULL)
+ PyDict_SetItemString(globals, "__builtins__", f->f_builtins);
+ if (PyCode_Check(prog)) {
+ if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "code object passed to exec may not contain free variables");
+ return -1;
+ }
+ v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals);
+ }
+ else if (PyFile_Check(prog)) {
+ FILE *fp = PyFile_AsFile(prog);
+ char *name = PyString_AsString(PyFile_Name(prog));
+ PyCompilerFlags cf;
+ if (name == NULL)
+ return -1;
+ cf.cf_flags = 0;
+ if (PyEval_MergeCompilerFlags(&cf))
+ v = PyRun_FileFlags(fp, name, Py_file_input, globals,
+ locals, &cf);
+ else
+ v = PyRun_File(fp, name, Py_file_input, globals,
+ locals);
+ }
+ else {
+ PyObject *tmp = NULL;
+ char *str;
+ PyCompilerFlags cf;
+ cf.cf_flags = 0;
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(prog)) {
+ tmp = PyUnicode_AsUTF8String(prog);
+ if (tmp == NULL)
+ return -1;
+ prog = tmp;
+ cf.cf_flags |= PyCF_SOURCE_IS_UTF8;
+ }
+#endif
+ if (PyString_AsStringAndSize(prog, &str, NULL))
+ return -1;
+ if (PyEval_MergeCompilerFlags(&cf))
+ v = PyRun_StringFlags(str, Py_file_input, globals,
+ locals, &cf);
+ else
+ v = PyRun_String(str, Py_file_input, globals, locals);
+ Py_XDECREF(tmp);
+ }
+ if (plain)
+ PyFrame_LocalsToFast(f, 0);
+ if (v == NULL)
+ return -1;
+ Py_DECREF(v);
+ return 0;
+}
+
+static void
+format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj)
+{
+ char *obj_str;
+
+ if (!obj)
+ return;
+
+ obj_str = PyString_AsString(obj);
+ if (!obj_str)
+ return;
+
+ PyErr_Format(exc, format_str, obj_str);
+}
+
+static PyObject *
+string_concatenate(PyObject *v, PyObject *w,
+ PyFrameObject *f, unsigned char *next_instr)
+{
+ /* This function implements 'variable += expr' when both arguments
+ are strings. */
+ Py_ssize_t v_len = PyString_GET_SIZE(v);
+ Py_ssize_t w_len = PyString_GET_SIZE(w);
+ Py_ssize_t new_len = v_len + w_len;
+ if (new_len < 0) {
+ PyErr_SetString(PyExc_OverflowError,
+ "strings are too large to concat");
+ return NULL;
+ }
+
+ if (v->ob_refcnt == 2) {
+ /* In the common case, there are 2 references to the value
+ * stored in 'variable' when the += is performed: one on the
+ * value stack (in 'v') and one still stored in the
+ * 'variable'. We try to delete the variable now to reduce
+ * the refcnt to 1.
+ */
+ switch (*next_instr) {
+ case STORE_FAST:
+ {
+ int oparg = PEEKARG();
+ PyObject **fastlocals = f->f_localsplus;
+ if (GETLOCAL(oparg) == v)
+ SETLOCAL(oparg, NULL);
+ break;
+ }
+ case STORE_DEREF:
+ {
+ PyObject **freevars = (f->f_localsplus +
+ f->f_code->co_nlocals);
+ PyObject *c = freevars[PEEKARG()];
+ if (PyCell_GET(c) == v)
+ PyCell_Set(c, NULL);
+ break;
+ }
+ case STORE_NAME:
+ {
+ PyObject *names = f->f_code->co_names;
+ PyObject *name = GETITEM(names, PEEKARG());
+ PyObject *locals = f->f_locals;
+ if (PyDict_CheckExact(locals) &&
+ PyDict_GetItem(locals, name) == v) {
+ if (PyDict_DelItem(locals, name) != 0) {
+ PyErr_Clear();
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) {
+ /* Now we own the last reference to 'v', so we can resize it
+ * in-place.
+ */
+ if (_PyString_Resize(&v, new_len) != 0) {
+ /* XXX if _PyString_Resize() fails, 'v' has been
+ * deallocated so it cannot be put back into
+ * 'variable'. The MemoryError is raised when there
+ * is no value in 'variable', which might (very
+ * remotely) be a cause of incompatibilities.
+ */
+ return NULL;
+ }
+ /* copy 'w' into the newly allocated area of 'v' */
+ memcpy(PyString_AS_STRING(v) + v_len,
+ PyString_AS_STRING(w), w_len);
+ return v;
+ }
+ else {
+ /* When in-place resizing is not an option. */
+ PyString_Concat(&v, w);
+ return v;
+ }
+}
+
+#ifdef DYNAMIC_EXECUTION_PROFILE
+
+static PyObject *
+getarray(long a[256])
+{
+ int i;
+ PyObject *l = PyList_New(256);
+ if (l == NULL) return NULL;
+ for (i = 0; i < 256; i++) {
+ PyObject *x = PyInt_FromLong(a[i]);
+ if (x == NULL) {
+ Py_DECREF(l);
+ return NULL;
+ }
+ PyList_SET_ITEM(l, i, x);
+ }
+ for (i = 0; i < 256; i++)
+ a[i] = 0;
+ return l;
+}
+
+PyObject *
+_Py_GetDXProfile(PyObject *self, PyObject *args)
+{
+#ifndef DXPAIRS
+ return getarray(dxp);
+#else
+ int i;
+ PyObject *l = PyList_New(257);
+ if (l == NULL) return NULL;
+ for (i = 0; i < 257; i++) {
+ PyObject *x = getarray(dxpairs[i]);
+ if (x == NULL) {
+ Py_DECREF(l);
+ return NULL;
+ }
+ PyList_SET_ITEM(l, i, x);
+ }
+ return l;
+#endif
+}
+
+#endif
diff --git a/contrib/tools/python/src/Python/codecs.c b/contrib/tools/python/src/Python/codecs.c
new file mode 100644
index 0000000000..dbecd1dccc
--- /dev/null
+++ b/contrib/tools/python/src/Python/codecs.c
@@ -0,0 +1,1045 @@
+/* ------------------------------------------------------------------------
+
+ Python Codec Registry and support functions
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+Copyright (c) Corporation for National Research Initiatives.
+
+ ------------------------------------------------------------------------ */
+
+#include "Python.h"
+#include <ctype.h>
+
+/* --- Codec Registry ----------------------------------------------------- */
+
+/* Import the standard encodings package which will register the first
+ codec search function.
+
+ This is done in a lazy way so that the Unicode implementation does
+ not downgrade startup time of scripts not needing it.
+
+ ImportErrors are silently ignored by this function. Only one try is
+ made.
+
+*/
+
+static int _PyCodecRegistry_Init(void); /* Forward */
+
+int PyCodec_Register(PyObject *search_function)
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
+ goto onError;
+ if (search_function == NULL) {
+ PyErr_BadArgument();
+ goto onError;
+ }
+ if (!PyCallable_Check(search_function)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be callable");
+ goto onError;
+ }
+ return PyList_Append(interp->codec_search_path, search_function);
+
+ onError:
+ return -1;
+}
+
+/* Convert a string to a normalized Python string: all characters are
+ converted to lower case, spaces are replaced with underscores. */
+
+static
+PyObject *normalizestring(const char *string)
+{
+ register size_t i;
+ size_t len = strlen(string);
+ char *p;
+ PyObject *v;
+
+ if (len > PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "string is too large");
+ return NULL;
+ }
+
+ v = PyString_FromStringAndSize(NULL, len);
+ if (v == NULL)
+ return NULL;
+ p = PyString_AS_STRING(v);
+ for (i = 0; i < len; i++) {
+ register char ch = string[i];
+ if (ch == ' ')
+ ch = '-';
+ else
+ ch = Py_TOLOWER(Py_CHARMASK(ch));
+ p[i] = ch;
+ }
+ return v;
+}
+
+/* Lookup the given encoding and return a tuple providing the codec
+ facilities.
+
+ The encoding string is looked up converted to all lower-case
+ characters. This makes encodings looked up through this mechanism
+ effectively case-insensitive.
+
+ If no codec is found, a LookupError is set and NULL returned.
+
+ As side effect, this tries to load the encodings package, if not
+ yet done. This is part of the lazy load strategy for the encodings
+ package.
+
+*/
+
+PyObject *_PyCodec_Lookup(const char *encoding)
+{
+ PyInterpreterState *interp;
+ PyObject *result, *args = NULL, *v;
+ Py_ssize_t i, len;
+
+ if (encoding == NULL) {
+ PyErr_BadArgument();
+ goto onError;
+ }
+
+ interp = PyThreadState_GET()->interp;
+ if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
+ goto onError;
+
+ /* Convert the encoding to a normalized Python string: all
+ characters are converted to lower case, spaces and hyphens are
+ replaced with underscores. */
+ v = normalizestring(encoding);
+ if (v == NULL)
+ goto onError;
+ PyString_InternInPlace(&v);
+
+ /* First, try to lookup the name in the registry dictionary */
+ result = PyDict_GetItem(interp->codec_search_cache, v);
+ if (result != NULL) {
+ Py_INCREF(result);
+ Py_DECREF(v);
+ return result;
+ }
+
+ /* Next, scan the search functions in order of registration */
+ args = PyTuple_New(1);
+ if (args == NULL)
+ goto onError;
+ PyTuple_SET_ITEM(args,0,v);
+
+ len = PyList_Size(interp->codec_search_path);
+ if (len < 0)
+ goto onError;
+ if (len == 0) {
+ PyErr_SetString(PyExc_LookupError,
+ "no codec search functions registered: "
+ "can't find encoding");
+ goto onError;
+ }
+
+ for (i = 0; i < len; i++) {
+ PyObject *func;
+
+ func = PyList_GetItem(interp->codec_search_path, i);
+ if (func == NULL)
+ goto onError;
+ result = PyEval_CallObject(func, args);
+ if (result == NULL)
+ goto onError;
+ if (result == Py_None) {
+ Py_DECREF(result);
+ continue;
+ }
+ if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 4) {
+ PyErr_SetString(PyExc_TypeError,
+ "codec search functions must return 4-tuples");
+ Py_DECREF(result);
+ goto onError;
+ }
+ break;
+ }
+ if (i == len) {
+ /* XXX Perhaps we should cache misses too ? */
+ PyErr_Format(PyExc_LookupError,
+ "unknown encoding: %s", encoding);
+ goto onError;
+ }
+
+ /* Cache and return the result */
+ PyDict_SetItem(interp->codec_search_cache, v, result);
+ Py_DECREF(args);
+ return result;
+
+ onError:
+ Py_XDECREF(args);
+ return NULL;
+}
+
+static
+PyObject *args_tuple(PyObject *object,
+ const char *errors)
+{
+ PyObject *args;
+
+ args = PyTuple_New(1 + (errors != NULL));
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(object);
+ PyTuple_SET_ITEM(args,0,object);
+ if (errors) {
+ PyObject *v;
+
+ v = PyString_FromString(errors);
+ if (v == NULL) {
+ Py_DECREF(args);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(args, 1, v);
+ }
+ return args;
+}
+
+/* Helper function to get a codec item */
+
+static
+PyObject *codec_getitem(const char *encoding, int index)
+{
+ PyObject *codecs;
+ PyObject *v;
+
+ codecs = _PyCodec_Lookup(encoding);
+ if (codecs == NULL)
+ return NULL;
+ v = PyTuple_GET_ITEM(codecs, index);
+ Py_DECREF(codecs);
+ Py_INCREF(v);
+ return v;
+}
+
+/* Helper functions to create an incremental codec. */
+static
+PyObject *codec_makeincrementalcodec(PyObject *codec_info,
+ const char *errors,
+ const char *attrname)
+{
+ PyObject *ret, *inccodec;
+
+ inccodec = PyObject_GetAttrString(codec_info, attrname);
+ if (inccodec == NULL)
+ return NULL;
+ if (errors)
+ ret = PyObject_CallFunction(inccodec, "s", errors);
+ else
+ ret = PyObject_CallFunction(inccodec, NULL);
+ Py_DECREF(inccodec);
+ return ret;
+}
+
+static
+PyObject *codec_getincrementalcodec(const char *encoding,
+ const char *errors,
+ const char *attrname)
+{
+ PyObject *codec_info, *ret;
+
+ codec_info = _PyCodec_Lookup(encoding);
+ if (codec_info == NULL)
+ return NULL;
+ ret = codec_makeincrementalcodec(codec_info, errors, attrname);
+ Py_DECREF(codec_info);
+ return ret;
+}
+
+/* Helper function to create a stream codec. */
+
+static
+PyObject *codec_getstreamcodec(const char *encoding,
+ PyObject *stream,
+ const char *errors,
+ const int index)
+{
+ PyObject *codecs, *streamcodec, *codeccls;
+
+ codecs = _PyCodec_Lookup(encoding);
+ if (codecs == NULL)
+ return NULL;
+
+ codeccls = PyTuple_GET_ITEM(codecs, index);
+ if (errors != NULL)
+ streamcodec = PyObject_CallFunction(codeccls, "Os", stream, errors);
+ else
+ streamcodec = PyObject_CallFunction(codeccls, "O", stream);
+ Py_DECREF(codecs);
+ return streamcodec;
+}
+
+/* Helpers to work with the result of _PyCodec_Lookup
+
+ */
+PyObject *_PyCodecInfo_GetIncrementalDecoder(PyObject *codec_info,
+ const char *errors)
+{
+ return codec_makeincrementalcodec(codec_info, errors,
+ "incrementaldecoder");
+}
+
+PyObject *_PyCodecInfo_GetIncrementalEncoder(PyObject *codec_info,
+ const char *errors)
+{
+ return codec_makeincrementalcodec(codec_info, errors,
+ "incrementalencoder");
+}
+
+
+/* Convenience APIs to query the Codec registry.
+
+ All APIs return a codec object with incremented refcount.
+
+ */
+
+PyObject *PyCodec_Encoder(const char *encoding)
+{
+ return codec_getitem(encoding, 0);
+}
+
+PyObject *PyCodec_Decoder(const char *encoding)
+{
+ return codec_getitem(encoding, 1);
+}
+
+PyObject *PyCodec_IncrementalEncoder(const char *encoding,
+ const char *errors)
+{
+ return codec_getincrementalcodec(encoding, errors, "incrementalencoder");
+}
+
+PyObject *PyCodec_IncrementalDecoder(const char *encoding,
+ const char *errors)
+{
+ return codec_getincrementalcodec(encoding, errors, "incrementaldecoder");
+}
+
+PyObject *PyCodec_StreamReader(const char *encoding,
+ PyObject *stream,
+ const char *errors)
+{
+ return codec_getstreamcodec(encoding, stream, errors, 2);
+}
+
+PyObject *PyCodec_StreamWriter(const char *encoding,
+ PyObject *stream,
+ const char *errors)
+{
+ return codec_getstreamcodec(encoding, stream, errors, 3);
+}
+
+/* Encode an object (e.g. a Unicode object) using the given encoding
+ and return the resulting encoded object (usually a Python string).
+
+ errors is passed to the encoder factory as argument if non-NULL. */
+
+static PyObject *
+_PyCodec_EncodeInternal(PyObject *object,
+ PyObject *encoder,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *args = NULL, *result = NULL;
+ PyObject *v;
+
+ args = args_tuple(object, errors);
+ if (args == NULL)
+ goto onError;
+
+ result = PyEval_CallObject(encoder,args);
+ if (result == NULL)
+ goto onError;
+
+ if (!PyTuple_Check(result) ||
+ PyTuple_GET_SIZE(result) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "encoder must return a tuple (object,integer)");
+ goto onError;
+ }
+ v = PyTuple_GET_ITEM(result,0);
+ Py_INCREF(v);
+ /* We don't check or use the second (integer) entry. */
+
+ Py_DECREF(args);
+ Py_DECREF(encoder);
+ Py_DECREF(result);
+ return v;
+
+ onError:
+ Py_XDECREF(result);
+ Py_XDECREF(args);
+ Py_XDECREF(encoder);
+ return NULL;
+}
+
+/* Decode an object (usually a Python string) using the given encoding
+ and return an equivalent object (e.g. a Unicode object).
+
+ errors is passed to the decoder factory as argument if non-NULL. */
+
+static PyObject *
+_PyCodec_DecodeInternal(PyObject *object,
+ PyObject *decoder,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *args = NULL, *result = NULL;
+ PyObject *v;
+
+ args = args_tuple(object, errors);
+ if (args == NULL)
+ goto onError;
+
+ result = PyEval_CallObject(decoder,args);
+ if (result == NULL)
+ goto onError;
+ if (!PyTuple_Check(result) ||
+ PyTuple_GET_SIZE(result) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "decoder must return a tuple (object,integer)");
+ goto onError;
+ }
+ v = PyTuple_GET_ITEM(result,0);
+ Py_INCREF(v);
+ /* We don't check or use the second (integer) entry. */
+
+ Py_DECREF(args);
+ Py_DECREF(decoder);
+ Py_DECREF(result);
+ return v;
+
+ onError:
+ Py_XDECREF(args);
+ Py_XDECREF(decoder);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+/* Generic encoding/decoding API */
+PyObject *PyCodec_Encode(PyObject *object,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *encoder;
+
+ encoder = PyCodec_Encoder(encoding);
+ if (encoder == NULL)
+ return NULL;
+
+ return _PyCodec_EncodeInternal(object, encoder, encoding, errors);
+}
+
+PyObject *PyCodec_Decode(PyObject *object,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *decoder;
+
+ decoder = PyCodec_Decoder(encoding);
+ if (decoder == NULL)
+ return NULL;
+
+ return _PyCodec_DecodeInternal(object, decoder, encoding, errors);
+}
+
+/* Text encoding/decoding API */
+PyObject * _PyCodec_LookupTextEncoding(const char *encoding,
+ const char *alternate_command)
+{
+ PyObject *codec;
+ PyObject *attr;
+ int is_text_codec;
+
+ codec = _PyCodec_Lookup(encoding);
+ if (codec == NULL)
+ return NULL;
+
+ /* Backwards compatibility: assume any raw tuple describes a text
+ * encoding, and the same for anything lacking the private
+ * attribute.
+ */
+ if (Py_Py3kWarningFlag && !PyTuple_CheckExact(codec)) {
+ attr = PyObject_GetAttrString(codec, "_is_text_encoding");
+ if (attr == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ goto onError;
+ PyErr_Clear();
+ } else {
+ is_text_codec = PyObject_IsTrue(attr);
+ Py_DECREF(attr);
+ if (is_text_codec < 0)
+ goto onError;
+ if (!is_text_codec) {
+ PyObject *msg = PyString_FromFormat(
+ "'%.400s' is not a text encoding; "
+ "use %s to handle arbitrary codecs",
+ encoding, alternate_command);
+ if (msg == NULL)
+ goto onError;
+ if (PyErr_WarnPy3k(PyString_AS_STRING(msg), 1) < 0) {
+ Py_DECREF(msg);
+ goto onError;
+ }
+ Py_DECREF(msg);
+ }
+ }
+ }
+
+ /* This appears to be a valid text encoding */
+ return codec;
+
+ onError:
+ Py_DECREF(codec);
+ return NULL;
+}
+
+
+static
+PyObject *codec_getitem_checked(const char *encoding,
+ const char *alternate_command,
+ int index)
+{
+ PyObject *codec;
+ PyObject *v;
+
+ codec = _PyCodec_LookupTextEncoding(encoding, alternate_command);
+ if (codec == NULL)
+ return NULL;
+
+ v = PyTuple_GET_ITEM(codec, index);
+ Py_INCREF(v);
+ Py_DECREF(codec);
+ return v;
+}
+
+static PyObject * _PyCodec_TextEncoder(const char *encoding)
+{
+ return codec_getitem_checked(encoding, "codecs.encode()", 0);
+}
+
+static PyObject * _PyCodec_TextDecoder(const char *encoding)
+{
+ return codec_getitem_checked(encoding, "codecs.decode()", 1);
+}
+
+PyObject *_PyCodec_EncodeText(PyObject *object,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *encoder;
+
+ encoder = _PyCodec_TextEncoder(encoding);
+ if (encoder == NULL)
+ return NULL;
+
+ return _PyCodec_EncodeInternal(object, encoder, encoding, errors);
+}
+
+PyObject *_PyCodec_DecodeText(PyObject *object,
+ const char *encoding,
+ const char *errors)
+{
+ PyObject *decoder;
+
+ decoder = _PyCodec_TextDecoder(encoding);
+ if (decoder == NULL)
+ return NULL;
+
+ return _PyCodec_DecodeInternal(object, decoder, encoding, errors);
+}
+
+/* Register the error handling callback function error under the name
+ name. This function will be called by the codec when it encounters
+ an unencodable characters/undecodable bytes and doesn't know the
+ callback name, when name is specified as the error parameter
+ in the call to the encode/decode function.
+ Return 0 on success, -1 on error */
+int PyCodec_RegisterError(const char *name, PyObject *error)
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
+ return -1;
+ if (!PyCallable_Check(error)) {
+ PyErr_SetString(PyExc_TypeError, "handler must be callable");
+ return -1;
+ }
+ return PyDict_SetItemString(interp->codec_error_registry,
+ (char *)name, error);
+}
+
+/* Lookup the error handling callback function registered under the
+ name error. As a special case NULL can be passed, in which case
+ the error handling callback for strict encoding will be returned. */
+PyObject *PyCodec_LookupError(const char *name)
+{
+ PyObject *handler = NULL;
+
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
+ return NULL;
+
+ if (name==NULL)
+ name = "strict";
+ handler = PyDict_GetItemString(interp->codec_error_registry, (char *)name);
+ if (!handler)
+ PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name);
+ else
+ Py_INCREF(handler);
+ return handler;
+}
+
+static void wrong_exception_type(PyObject *exc)
+{
+ PyObject *type = PyObject_GetAttrString(exc, "__class__");
+ if (type != NULL) {
+ PyObject *name = PyObject_GetAttrString(type, "__name__");
+ Py_DECREF(type);
+ if (name != NULL) {
+ PyObject *string = PyObject_Str(name);
+ Py_DECREF(name);
+ if (string != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "don't know how to handle %.400s in error callback",
+ PyString_AS_STRING(string));
+ Py_DECREF(string);
+ }
+ }
+ }
+}
+
+PyObject *PyCodec_StrictErrors(PyObject *exc)
+{
+ if (PyExceptionInstance_Check(exc))
+ PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
+ else
+ PyErr_SetString(PyExc_TypeError, "codec must pass exception instance");
+ return NULL;
+}
+
+
+#ifdef Py_USING_UNICODE
+PyObject *PyCodec_IgnoreErrors(PyObject *exc)
+{
+ Py_ssize_t end;
+
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
+ if (PyUnicodeEncodeError_GetEnd(exc, &end))
+ return NULL;
+ }
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) {
+ if (PyUnicodeDecodeError_GetEnd(exc, &end))
+ return NULL;
+ }
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) {
+ if (PyUnicodeTranslateError_GetEnd(exc, &end))
+ return NULL;
+ }
+ else {
+ wrong_exception_type(exc);
+ return NULL;
+ }
+ /* ouch: passing NULL, 0, pos gives None instead of u'' */
+ return Py_BuildValue("(u#n)", &end, 0, end);
+}
+
+
+PyObject *PyCodec_ReplaceErrors(PyObject *exc)
+{
+ PyObject *restuple;
+ Py_ssize_t start;
+ Py_ssize_t end;
+ Py_ssize_t i;
+
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
+ PyObject *res;
+ Py_UNICODE *p;
+ if (PyUnicodeEncodeError_GetStart(exc, &start))
+ return NULL;
+ if (PyUnicodeEncodeError_GetEnd(exc, &end))
+ return NULL;
+ res = PyUnicode_FromUnicode(NULL, end-start);
+ if (res == NULL)
+ return NULL;
+ for (p = PyUnicode_AS_UNICODE(res), i = start;
+ i<end; ++p, ++i)
+ *p = '?';
+ restuple = Py_BuildValue("(On)", res, end);
+ Py_DECREF(res);
+ return restuple;
+ }
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) {
+ Py_UNICODE res = Py_UNICODE_REPLACEMENT_CHARACTER;
+ if (PyUnicodeDecodeError_GetEnd(exc, &end))
+ return NULL;
+ return Py_BuildValue("(u#n)", &res, (Py_ssize_t)1, end);
+ }
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) {
+ PyObject *res;
+ Py_UNICODE *p;
+ if (PyUnicodeTranslateError_GetStart(exc, &start))
+ return NULL;
+ if (PyUnicodeTranslateError_GetEnd(exc, &end))
+ return NULL;
+ res = PyUnicode_FromUnicode(NULL, end-start);
+ if (res == NULL)
+ return NULL;
+ for (p = PyUnicode_AS_UNICODE(res), i = start;
+ i<end; ++p, ++i)
+ *p = Py_UNICODE_REPLACEMENT_CHARACTER;
+ restuple = Py_BuildValue("(On)", res, end);
+ Py_DECREF(res);
+ return restuple;
+ }
+ else {
+ wrong_exception_type(exc);
+ return NULL;
+ }
+}
+
+PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc)
+{
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
+ PyObject *restuple;
+ PyObject *object;
+ Py_ssize_t start;
+ Py_ssize_t end;
+ PyObject *res;
+ Py_UNICODE *p;
+ Py_UNICODE *startp;
+ Py_UNICODE *e;
+ Py_UNICODE *outp;
+ Py_ssize_t ressize;
+ if (PyUnicodeEncodeError_GetStart(exc, &start))
+ return NULL;
+ if (PyUnicodeEncodeError_GetEnd(exc, &end))
+ return NULL;
+ if (!(object = PyUnicodeEncodeError_GetObject(exc)))
+ return NULL;
+ startp = PyUnicode_AS_UNICODE(object);
+ if (end - start > PY_SSIZE_T_MAX / (2+7+1)) {
+ end = start + PY_SSIZE_T_MAX / (2+7+1);
+#ifndef Py_UNICODE_WIDE
+ if (0xD800 <= startp[end - 1] && startp[end - 1] <= 0xDBFF)
+ end--;
+#endif
+ }
+ e = startp + end;
+ for (p = startp+start, ressize = 0; p < e;) {
+ Py_UCS4 ch = *p++;
+#ifndef Py_UNICODE_WIDE
+ if ((0xD800 <= ch && ch <= 0xDBFF) &&
+ (p < e) &&
+ (0xDC00 <= *p && *p <= 0xDFFF)) {
+ ch = ((((ch & 0x03FF) << 10) |
+ ((Py_UCS4)*p++ & 0x03FF)) + 0x10000);
+ }
+#endif
+ if (ch < 10)
+ ressize += 2+1+1;
+ else if (ch < 100)
+ ressize += 2+2+1;
+ else if (ch < 1000)
+ ressize += 2+3+1;
+ else if (ch < 10000)
+ ressize += 2+4+1;
+ else if (ch < 100000)
+ ressize += 2+5+1;
+ else if (ch < 1000000)
+ ressize += 2+6+1;
+ else
+ ressize += 2+7+1;
+ }
+ /* allocate replacement */
+ res = PyUnicode_FromUnicode(NULL, ressize);
+ if (res == NULL) {
+ Py_DECREF(object);
+ return NULL;
+ }
+ /* generate replacement */
+ for (p = startp+start, outp = PyUnicode_AS_UNICODE(res); p < e;) {
+ int digits;
+ int base;
+ Py_UCS4 ch = *p++;
+#ifndef Py_UNICODE_WIDE
+ if ((0xD800 <= ch && ch <= 0xDBFF) &&
+ (p < startp+end) &&
+ (0xDC00 <= *p && *p <= 0xDFFF)) {
+ ch = ((((ch & 0x03FF) << 10) |
+ ((Py_UCS4)*p++ & 0x03FF)) + 0x10000);
+ }
+#endif
+ *outp++ = '&';
+ *outp++ = '#';
+ if (ch < 10) {
+ digits = 1;
+ base = 1;
+ }
+ else if (ch < 100) {
+ digits = 2;
+ base = 10;
+ }
+ else if (ch < 1000) {
+ digits = 3;
+ base = 100;
+ }
+ else if (ch < 10000) {
+ digits = 4;
+ base = 1000;
+ }
+ else if (ch < 100000) {
+ digits = 5;
+ base = 10000;
+ }
+ else if (ch < 1000000) {
+ digits = 6;
+ base = 100000;
+ }
+ else {
+ digits = 7;
+ base = 1000000;
+ }
+ while (digits-->0) {
+ *outp++ = '0' + ch/base;
+ ch %= base;
+ base /= 10;
+ }
+ *outp++ = ';';
+ }
+ restuple = Py_BuildValue("(On)", res, end);
+ Py_DECREF(res);
+ Py_DECREF(object);
+ return restuple;
+ }
+ else {
+ wrong_exception_type(exc);
+ return NULL;
+ }
+}
+
+static Py_UNICODE hexdigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)
+{
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
+ PyObject *restuple;
+ PyObject *object;
+ Py_ssize_t start;
+ Py_ssize_t end;
+ PyObject *res;
+ Py_UNICODE *p;
+ Py_UNICODE *startp;
+ Py_UNICODE *outp;
+ Py_ssize_t ressize;
+ if (PyUnicodeEncodeError_GetStart(exc, &start))
+ return NULL;
+ if (PyUnicodeEncodeError_GetEnd(exc, &end))
+ return NULL;
+ if (!(object = PyUnicodeEncodeError_GetObject(exc)))
+ return NULL;
+ if (end - start > PY_SSIZE_T_MAX / (1+1+8))
+ end = start + PY_SSIZE_T_MAX / (1+1+8);
+ startp = PyUnicode_AS_UNICODE(object);
+ for (p = startp+start, ressize = 0; p < startp+end; ++p) {
+#ifdef Py_UNICODE_WIDE
+ if (*p >= 0x00010000)
+ ressize += 1+1+8;
+ else
+#endif
+ if (*p >= 0x100) {
+ ressize += 1+1+4;
+ }
+ else
+ ressize += 1+1+2;
+ }
+ res = PyUnicode_FromUnicode(NULL, ressize);
+ if (res == NULL) {
+ Py_DECREF(object);
+ return NULL;
+ }
+ for (p = startp+start, outp = PyUnicode_AS_UNICODE(res);
+ p < startp+end; ++p) {
+ Py_UNICODE c = *p;
+ *outp++ = '\\';
+#ifdef Py_UNICODE_WIDE
+ if (c >= 0x00010000) {
+ *outp++ = 'U';
+ *outp++ = hexdigits[(c>>28)&0xf];
+ *outp++ = hexdigits[(c>>24)&0xf];
+ *outp++ = hexdigits[(c>>20)&0xf];
+ *outp++ = hexdigits[(c>>16)&0xf];
+ *outp++ = hexdigits[(c>>12)&0xf];
+ *outp++ = hexdigits[(c>>8)&0xf];
+ }
+ else
+#endif
+ if (c >= 0x100) {
+ *outp++ = 'u';
+ *outp++ = hexdigits[(c>>12)&0xf];
+ *outp++ = hexdigits[(c>>8)&0xf];
+ }
+ else
+ *outp++ = 'x';
+ *outp++ = hexdigits[(c>>4)&0xf];
+ *outp++ = hexdigits[c&0xf];
+ }
+
+ restuple = Py_BuildValue("(On)", res, end);
+ Py_DECREF(res);
+ Py_DECREF(object);
+ return restuple;
+ }
+ else {
+ wrong_exception_type(exc);
+ return NULL;
+ }
+}
+#endif
+
+static PyObject *strict_errors(PyObject *self, PyObject *exc)
+{
+ return PyCodec_StrictErrors(exc);
+}
+
+
+#ifdef Py_USING_UNICODE
+static PyObject *ignore_errors(PyObject *self, PyObject *exc)
+{
+ return PyCodec_IgnoreErrors(exc);
+}
+
+
+static PyObject *replace_errors(PyObject *self, PyObject *exc)
+{
+ return PyCodec_ReplaceErrors(exc);
+}
+
+
+static PyObject *xmlcharrefreplace_errors(PyObject *self, PyObject *exc)
+{
+ return PyCodec_XMLCharRefReplaceErrors(exc);
+}
+
+
+static PyObject *backslashreplace_errors(PyObject *self, PyObject *exc)
+{
+ return PyCodec_BackslashReplaceErrors(exc);
+}
+#endif
+
+static int _PyCodecRegistry_Init(void)
+{
+ static struct {
+ char *name;
+ PyMethodDef def;
+ } methods[] =
+ {
+ {
+ "strict",
+ {
+ "strict_errors",
+ strict_errors,
+ METH_O,
+ PyDoc_STR("Implements the 'strict' error handling, which "
+ "raises a UnicodeError on coding errors.")
+ }
+ },
+#ifdef Py_USING_UNICODE
+ {
+ "ignore",
+ {
+ "ignore_errors",
+ ignore_errors,
+ METH_O,
+ PyDoc_STR("Implements the 'ignore' error handling, which "
+ "ignores malformed data and continues.")
+ }
+ },
+ {
+ "replace",
+ {
+ "replace_errors",
+ replace_errors,
+ METH_O,
+ PyDoc_STR("Implements the 'replace' error handling, which "
+ "replaces malformed data with a replacement marker.")
+ }
+ },
+ {
+ "xmlcharrefreplace",
+ {
+ "xmlcharrefreplace_errors",
+ xmlcharrefreplace_errors,
+ METH_O,
+ PyDoc_STR("Implements the 'xmlcharrefreplace' error handling, "
+ "which replaces an unencodable character with the "
+ "appropriate XML character reference.")
+ }
+ },
+ {
+ "backslashreplace",
+ {
+ "backslashreplace_errors",
+ backslashreplace_errors,
+ METH_O,
+ PyDoc_STR("Implements the 'backslashreplace' error handling, "
+ "which replaces an unencodable character with a "
+ "backslashed escape sequence.")
+ }
+ }
+#endif
+ };
+
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ PyObject *mod;
+ unsigned i;
+
+ if (interp->codec_search_path != NULL)
+ return 0;
+
+ interp->codec_search_path = PyList_New(0);
+ interp->codec_search_cache = PyDict_New();
+ interp->codec_error_registry = PyDict_New();
+
+ if (interp->codec_error_registry) {
+ for (i = 0; i < sizeof(methods)/sizeof(methods[0]); ++i) {
+ PyObject *func = PyCFunction_New(&methods[i].def, NULL);
+ int res;
+ if (!func)
+ Py_FatalError("can't initialize codec error registry");
+ res = PyCodec_RegisterError(methods[i].name, func);
+ Py_DECREF(func);
+ if (res)
+ Py_FatalError("can't initialize codec error registry");
+ }
+ }
+
+ if (interp->codec_search_path == NULL ||
+ interp->codec_search_cache == NULL ||
+ interp->codec_error_registry == NULL)
+ Py_FatalError("can't initialize codec registry");
+
+ mod = PyImport_ImportModuleLevel("encodings", NULL, NULL, NULL, 0);
+ if (mod == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_ImportError)) {
+ /* Ignore ImportErrors... this is done so that
+ distributions can disable the encodings package. Note
+ that other errors are not masked, e.g. SystemErrors
+ raised to inform the user of an error in the Python
+ configuration are still reported back to the user. */
+ PyErr_Clear();
+ return 0;
+ }
+ return -1;
+ }
+ Py_DECREF(mod);
+ return 0;
+}
diff --git a/contrib/tools/python/src/Python/compile.c b/contrib/tools/python/src/Python/compile.c
new file mode 100644
index 0000000000..7f8babc12b
--- /dev/null
+++ b/contrib/tools/python/src/Python/compile.c
@@ -0,0 +1,3976 @@
+/*
+ * This file compiles an abstract syntax tree (AST) into Python bytecode.
+ *
+ * The primary entry point is PyAST_Compile(), which returns a
+ * PyCodeObject. The compiler makes several passes to build the code
+ * object:
+ * 1. Checks for future statements. See future.c
+ * 2. Builds a symbol table. See symtable.c.
+ * 3. Generate code for basic blocks. See compiler_mod() in this file.
+ * 4. Assemble the basic blocks into final code. See assemble() in
+ * this file.
+ * 5. Optimize the byte code (peephole optimizations). See peephole.c
+ *
+ * Note that compiler_mod() suggests module, but the module ast type
+ * (mod_ty) has cases for expressions and interactive statements.
+ *
+ * CAUTION: The VISIT_* macros abort the current function when they
+ * encounter a problem. So don't invoke them when there is memory
+ * which needs to be released. Code blocks are OK, as the compiler
+ * structure takes care of releasing those. Use the arena to manage
+ * objects.
+ */
+
+#include "Python.h"
+
+#include "Python-ast.h"
+#include "node.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+#include "opcode.h"
+
+int Py_OptimizeFlag = 0;
+
+#define DEFAULT_BLOCK_SIZE 16
+#define DEFAULT_BLOCKS 8
+#define DEFAULT_CODE_SIZE 128
+#define DEFAULT_LNOTAB_SIZE 16
+
+#define COMP_GENEXP 0
+#define COMP_SETCOMP 1
+#define COMP_DICTCOMP 2
+
+struct instr {
+ unsigned i_jabs : 1;
+ unsigned i_jrel : 1;
+ unsigned i_hasarg : 1;
+ unsigned char i_opcode;
+ int i_oparg;
+ struct basicblock_ *i_target; /* target block (if jump instruction) */
+ int i_lineno;
+};
+
+typedef struct basicblock_ {
+ /* Each basicblock in a compilation unit is linked via b_list in the
+ reverse order that the block are allocated. b_list points to the next
+ block, not to be confused with b_next, which is next by control flow. */
+ struct basicblock_ *b_list;
+ /* number of instructions used */
+ int b_iused;
+ /* length of instruction array (b_instr) */
+ int b_ialloc;
+ /* pointer to an array of instructions, initially NULL */
+ struct instr *b_instr;
+ /* If b_next is non-NULL, it is a pointer to the next
+ block reached by normal control flow. */
+ struct basicblock_ *b_next;
+ /* b_seen is used to perform a DFS of basicblocks. */
+ unsigned b_seen : 1;
+ /* b_return is true if a RETURN_VALUE opcode is inserted. */
+ unsigned b_return : 1;
+ /* depth of stack upon entry of block, computed by stackdepth() */
+ int b_startdepth;
+ /* instruction offset for block, computed by assemble_jump_offsets() */
+ int b_offset;
+} basicblock;
+
+/* fblockinfo tracks the current frame block.
+
+A frame block is used to handle loops, try/except, and try/finally.
+It's called a frame block to distinguish it from a basic block in the
+compiler IR.
+*/
+
+enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END };
+
+struct fblockinfo {
+ enum fblocktype fb_type;
+ basicblock *fb_block;
+};
+
+/* The following items change on entry and exit of code blocks.
+ They must be saved and restored when returning to a block.
+*/
+struct compiler_unit {
+ PySTEntryObject *u_ste;
+
+ PyObject *u_name;
+ /* The following fields are dicts that map objects to
+ the index of them in co_XXX. The index is used as
+ the argument for opcodes that refer to those collections.
+ */
+ PyObject *u_consts; /* all constants */
+ PyObject *u_names; /* all names */
+ PyObject *u_varnames; /* local variables */
+ PyObject *u_cellvars; /* cell variables */
+ PyObject *u_freevars; /* free variables */
+
+ PyObject *u_private; /* for private name mangling */
+
+ int u_argcount; /* number of arguments for block */
+ /* Pointer to the most recently allocated block. By following b_list
+ members, you can reach all early allocated blocks. */
+ basicblock *u_blocks;
+ basicblock *u_curblock; /* pointer to current block */
+
+ int u_nfblocks;
+ struct fblockinfo u_fblock[CO_MAXBLOCKS];
+
+ int u_firstlineno; /* the first lineno of the block */
+ int u_lineno; /* the lineno for the current stmt */
+ bool u_lineno_set; /* boolean to indicate whether instr
+ has been generated with current lineno */
+};
+
+/* This struct captures the global state of a compilation.
+
+The u pointer points to the current compilation unit, while units
+for enclosing blocks are stored in c_stack. The u and c_stack are
+managed by compiler_enter_scope() and compiler_exit_scope().
+*/
+
+struct compiler {
+ const char *c_filename;
+ struct symtable *c_st;
+ PyFutureFeatures *c_future; /* pointer to module's __future__ */
+ PyCompilerFlags *c_flags;
+
+ int c_interactive; /* true if in interactive mode */
+ int c_nestlevel;
+
+ struct compiler_unit *u; /* compiler state for current block */
+ PyObject *c_stack; /* Python list holding compiler_unit ptrs */
+ PyArena *c_arena; /* pointer to memory allocation arena */
+};
+
+static int compiler_enter_scope(struct compiler *, identifier, void *, int);
+static void compiler_free(struct compiler *);
+static basicblock *compiler_new_block(struct compiler *);
+static int compiler_next_instr(struct compiler *, basicblock *);
+static int compiler_addop(struct compiler *, int);
+static int compiler_addop_o(struct compiler *, int, PyObject *, PyObject *);
+static int compiler_addop_i(struct compiler *, int, int);
+static int compiler_addop_j(struct compiler *, int, basicblock *, int);
+static basicblock *compiler_use_new_block(struct compiler *);
+static int compiler_error(struct compiler *, const char *);
+static int compiler_nameop(struct compiler *, identifier, expr_context_ty);
+
+static PyCodeObject *compiler_mod(struct compiler *, mod_ty);
+static int compiler_visit_stmt(struct compiler *, stmt_ty);
+static int compiler_visit_keyword(struct compiler *, keyword_ty);
+static int compiler_visit_expr(struct compiler *, expr_ty);
+static int compiler_augassign(struct compiler *, stmt_ty);
+static int compiler_visit_slice(struct compiler *, slice_ty,
+ expr_context_ty);
+
+static int compiler_push_fblock(struct compiler *, enum fblocktype,
+ basicblock *);
+static void compiler_pop_fblock(struct compiler *, enum fblocktype,
+ basicblock *);
+/* Returns true if there is a loop on the fblock stack. */
+static int compiler_in_loop(struct compiler *);
+
+static int inplace_binop(struct compiler *, operator_ty);
+static int expr_constant(expr_ty e);
+
+static int compiler_with(struct compiler *, stmt_ty);
+
+static PyCodeObject *assemble(struct compiler *, int addNone);
+static PyObject *__doc__;
+
+#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit"
+
+PyObject *
+_Py_Mangle(PyObject *privateobj, PyObject *ident)
+{
+ /* Name mangling: __private becomes _classname__private.
+ This is independent from how the name is used. */
+ const char *p, *name = PyString_AsString(ident);
+ char *buffer;
+ size_t nlen, plen;
+ if (privateobj == NULL || !PyString_Check(privateobj) ||
+ name == NULL || name[0] != '_' || name[1] != '_') {
+ Py_INCREF(ident);
+ return ident;
+ }
+ p = PyString_AsString(privateobj);
+ nlen = strlen(name);
+ /* Don't mangle __id__ or names with dots.
+
+ The only time a name with a dot can occur is when
+ we are compiling an import statement that has a
+ package name.
+
+ TODO(jhylton): Decide whether we want to support
+ mangling of the module name, e.g. __M.X.
+ */
+ if ((name[nlen-1] == '_' && name[nlen-2] == '_')
+ || strchr(name, '.')) {
+ Py_INCREF(ident);
+ return ident; /* Don't mangle __whatever__ */
+ }
+ /* Strip leading underscores from class name */
+ while (*p == '_')
+ p++;
+ if (*p == '\0') {
+ Py_INCREF(ident);
+ return ident; /* Don't mangle if class is just underscores */
+ }
+ plen = strlen(p);
+
+ if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
+ PyErr_SetString(PyExc_OverflowError,
+ "private identifier too large to be mangled");
+ return NULL;
+ }
+
+ ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen);
+ if (!ident)
+ return 0;
+ /* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */
+ buffer = PyString_AS_STRING(ident);
+ buffer[0] = '_';
+ strncpy(buffer+1, p, plen);
+ strcpy(buffer+1+plen, name);
+ return ident;
+}
+
+static int
+compiler_init(struct compiler *c)
+{
+ memset(c, 0, sizeof(struct compiler));
+
+ c->c_stack = PyList_New(0);
+ if (!c->c_stack)
+ return 0;
+
+ return 1;
+}
+
+PyCodeObject *
+PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags,
+ PyArena *arena)
+{
+ struct compiler c;
+ PyCodeObject *co = NULL;
+ PyCompilerFlags local_flags;
+ int merged;
+
+ if (!__doc__) {
+ __doc__ = PyString_InternFromString("__doc__");
+ if (!__doc__)
+ return NULL;
+ }
+
+ if (!compiler_init(&c))
+ return NULL;
+ c.c_filename = filename;
+ c.c_arena = arena;
+ c.c_future = PyFuture_FromAST(mod, filename);
+ if (c.c_future == NULL)
+ goto finally;
+ if (!flags) {
+ local_flags.cf_flags = 0;
+ flags = &local_flags;
+ }
+ merged = c.c_future->ff_features | flags->cf_flags;
+ c.c_future->ff_features = merged;
+ flags->cf_flags = merged;
+ c.c_flags = flags;
+ c.c_nestlevel = 0;
+
+ c.c_st = PySymtable_Build(mod, filename, c.c_future);
+ if (c.c_st == NULL) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_SystemError, "no symtable");
+ goto finally;
+ }
+
+ co = compiler_mod(&c, mod);
+
+ finally:
+ compiler_free(&c);
+ assert(co || PyErr_Occurred());
+ return co;
+}
+
+PyCodeObject *
+PyNode_Compile(struct _node *n, const char *filename)
+{
+ PyCodeObject *co = NULL;
+ mod_ty mod;
+ PyArena *arena = PyArena_New();
+ if (!arena)
+ return NULL;
+ mod = PyAST_FromNode(n, NULL, filename, arena);
+ if (mod)
+ co = PyAST_Compile(mod, filename, NULL, arena);
+ PyArena_Free(arena);
+ return co;
+}
+
+static void
+compiler_free(struct compiler *c)
+{
+ if (c->c_st)
+ PySymtable_Free(c->c_st);
+ if (c->c_future)
+ PyObject_Free(c->c_future);
+ Py_DECREF(c->c_stack);
+}
+
+static PyObject *
+list2dict(PyObject *list)
+{
+ Py_ssize_t i, n;
+ PyObject *v, *k;
+ PyObject *dict = PyDict_New();
+ if (!dict) return NULL;
+
+ n = PyList_Size(list);
+ for (i = 0; i < n; i++) {
+ v = PyInt_FromLong(i);
+ if (!v) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ k = PyList_GET_ITEM(list, i);
+ k = _PyCode_ConstantKey(k);
+ if (k == NULL || PyDict_SetItem(dict, k, v) < 0) {
+ Py_XDECREF(k);
+ Py_DECREF(v);
+ Py_DECREF(dict);
+ return NULL;
+ }
+ Py_DECREF(k);
+ Py_DECREF(v);
+ }
+ return dict;
+}
+
+/* Return new dict containing names from src that match scope(s).
+
+src is a symbol table dictionary. If the scope of a name matches
+either scope_type or flag is set, insert it into the new dict. The
+values are integers, starting at offset and increasing by one for
+each key.
+*/
+
+static PyObject *
+dictbytype(PyObject *src, int scope_type, int flag, int offset)
+{
+ Py_ssize_t i = offset, scope, num_keys, key_i;
+ PyObject *k, *v, *dest = PyDict_New();
+ PyObject *sorted_keys;
+
+ assert(offset >= 0);
+ if (dest == NULL)
+ return NULL;
+
+ /* Sort the keys so that we have a deterministic order on the indexes
+ saved in the returned dictionary. These indexes are used as indexes
+ into the free and cell var storage. Therefore if they aren't
+ deterministic, then the generated bytecode is not deterministic.
+ */
+ sorted_keys = PyDict_Keys(src);
+ if (sorted_keys == NULL)
+ return NULL;
+ if (PyList_Sort(sorted_keys) != 0) {
+ Py_DECREF(sorted_keys);
+ return NULL;
+ }
+ num_keys = PyList_GET_SIZE(sorted_keys);
+
+ for (key_i = 0; key_i < num_keys; key_i++) {
+ k = PyList_GET_ITEM(sorted_keys, key_i);
+ v = PyDict_GetItem(src, k);
+ /* XXX this should probably be a macro in symtable.h */
+ assert(PyInt_Check(v));
+ scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK;
+
+ if (scope == scope_type || PyInt_AS_LONG(v) & flag) {
+ PyObject *tuple, *item = PyInt_FromLong(i);
+ if (item == NULL) {
+ Py_DECREF(sorted_keys);
+ Py_DECREF(dest);
+ return NULL;
+ }
+ i++;
+ tuple = _PyCode_ConstantKey(k);
+ if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) {
+ Py_DECREF(sorted_keys);
+ Py_DECREF(item);
+ Py_DECREF(dest);
+ Py_XDECREF(tuple);
+ return NULL;
+ }
+ Py_DECREF(item);
+ Py_DECREF(tuple);
+ }
+ }
+ Py_DECREF(sorted_keys);
+ return dest;
+}
+
+static void
+compiler_unit_check(struct compiler_unit *u)
+{
+ basicblock *block;
+ for (block = u->u_blocks; block != NULL; block = block->b_list) {
+ assert((void *)block != (void *)0xcbcbcbcb);
+ assert((void *)block != (void *)0xfbfbfbfb);
+ assert((void *)block != (void *)0xdbdbdbdb);
+ if (block->b_instr != NULL) {
+ assert(block->b_ialloc > 0);
+ assert(block->b_iused > 0);
+ assert(block->b_ialloc >= block->b_iused);
+ }
+ else {
+ assert (block->b_iused == 0);
+ assert (block->b_ialloc == 0);
+ }
+ }
+}
+
+static void
+compiler_unit_free(struct compiler_unit *u)
+{
+ basicblock *b, *next;
+
+ compiler_unit_check(u);
+ b = u->u_blocks;
+ while (b != NULL) {
+ if (b->b_instr)
+ PyObject_Free((void *)b->b_instr);
+ next = b->b_list;
+ PyObject_Free((void *)b);
+ b = next;
+ }
+ Py_CLEAR(u->u_ste);
+ Py_CLEAR(u->u_name);
+ Py_CLEAR(u->u_consts);
+ Py_CLEAR(u->u_names);
+ Py_CLEAR(u->u_varnames);
+ Py_CLEAR(u->u_freevars);
+ Py_CLEAR(u->u_cellvars);
+ Py_CLEAR(u->u_private);
+ PyObject_Free(u);
+}
+
+static int
+compiler_enter_scope(struct compiler *c, identifier name, void *key,
+ int lineno)
+{
+ struct compiler_unit *u;
+
+ u = (struct compiler_unit *)PyObject_Malloc(sizeof(
+ struct compiler_unit));
+ if (!u) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ memset(u, 0, sizeof(struct compiler_unit));
+ u->u_argcount = 0;
+ u->u_ste = PySymtable_Lookup(c->c_st, key);
+ if (!u->u_ste) {
+ compiler_unit_free(u);
+ return 0;
+ }
+ Py_INCREF(name);
+ u->u_name = name;
+ u->u_varnames = list2dict(u->u_ste->ste_varnames);
+ u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0);
+ if (!u->u_varnames || !u->u_cellvars) {
+ compiler_unit_free(u);
+ return 0;
+ }
+
+ u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
+ PyDict_Size(u->u_cellvars));
+ if (!u->u_freevars) {
+ compiler_unit_free(u);
+ return 0;
+ }
+
+ u->u_blocks = NULL;
+ u->u_nfblocks = 0;
+ u->u_firstlineno = lineno;
+ u->u_lineno = 0;
+ u->u_lineno_set = false;
+ u->u_consts = PyDict_New();
+ if (!u->u_consts) {
+ compiler_unit_free(u);
+ return 0;
+ }
+ u->u_names = PyDict_New();
+ if (!u->u_names) {
+ compiler_unit_free(u);
+ return 0;
+ }
+
+ u->u_private = NULL;
+
+ /* Push the old compiler_unit on the stack. */
+ if (c->u) {
+ PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL);
+ if (!capsule || PyList_Append(c->c_stack, capsule) < 0) {
+ Py_XDECREF(capsule);
+ compiler_unit_free(u);
+ return 0;
+ }
+ Py_DECREF(capsule);
+ u->u_private = c->u->u_private;
+ Py_XINCREF(u->u_private);
+ }
+ c->u = u;
+
+ c->c_nestlevel++;
+ if (compiler_use_new_block(c) == NULL)
+ return 0;
+
+ return 1;
+}
+
+static void
+compiler_exit_scope(struct compiler *c)
+{
+ int n;
+ PyObject *capsule;
+
+ c->c_nestlevel--;
+ compiler_unit_free(c->u);
+ /* Restore c->u to the parent unit. */
+ n = PyList_GET_SIZE(c->c_stack) - 1;
+ if (n >= 0) {
+ capsule = PyList_GET_ITEM(c->c_stack, n);
+ c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
+ assert(c->u);
+ /* we are deleting from a list so this really shouldn't fail */
+ if (PySequence_DelItem(c->c_stack, n) < 0)
+ Py_FatalError("compiler_exit_scope()");
+ compiler_unit_check(c->u);
+ }
+ else
+ c->u = NULL;
+
+}
+
+/* Allocate a new block and return a pointer to it.
+ Returns NULL on error.
+*/
+
+static basicblock *
+compiler_new_block(struct compiler *c)
+{
+ basicblock *b;
+ struct compiler_unit *u;
+
+ u = c->u;
+ b = (basicblock *)PyObject_Malloc(sizeof(basicblock));
+ if (b == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset((void *)b, 0, sizeof(basicblock));
+ /* Extend the singly linked list of blocks with new block. */
+ b->b_list = u->u_blocks;
+ u->u_blocks = b;
+ return b;
+}
+
+static basicblock *
+compiler_use_new_block(struct compiler *c)
+{
+ basicblock *block = compiler_new_block(c);
+ if (block == NULL)
+ return NULL;
+ c->u->u_curblock = block;
+ return block;
+}
+
+static basicblock *
+compiler_next_block(struct compiler *c)
+{
+ basicblock *block = compiler_new_block(c);
+ if (block == NULL)
+ return NULL;
+ c->u->u_curblock->b_next = block;
+ c->u->u_curblock = block;
+ return block;
+}
+
+static basicblock *
+compiler_use_next_block(struct compiler *c, basicblock *block)
+{
+ assert(block != NULL);
+ c->u->u_curblock->b_next = block;
+ c->u->u_curblock = block;
+ return block;
+}
+
+/* Returns the offset of the next instruction in the current block's
+ b_instr array. Resizes the b_instr as necessary.
+ Returns -1 on failure.
+*/
+
+static int
+compiler_next_instr(struct compiler *c, basicblock *b)
+{
+ assert(b != NULL);
+ if (b->b_instr == NULL) {
+ b->b_instr = (struct instr *)PyObject_Malloc(
+ sizeof(struct instr) * DEFAULT_BLOCK_SIZE);
+ if (b->b_instr == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ b->b_ialloc = DEFAULT_BLOCK_SIZE;
+ memset((char *)b->b_instr, 0,
+ sizeof(struct instr) * DEFAULT_BLOCK_SIZE);
+ }
+ else if (b->b_iused == b->b_ialloc) {
+ struct instr *tmp;
+ size_t oldsize, newsize;
+ oldsize = b->b_ialloc * sizeof(struct instr);
+ newsize = oldsize << 1;
+
+ if (oldsize > (PY_SIZE_MAX >> 1)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ if (newsize == 0) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ b->b_ialloc <<= 1;
+ tmp = (struct instr *)PyObject_Realloc(
+ (void *)b->b_instr, newsize);
+ if (tmp == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ b->b_instr = tmp;
+ memset((char *)b->b_instr + oldsize, 0, newsize - oldsize);
+ }
+ return b->b_iused++;
+}
+
+/* Set the i_lineno member of the instruction at offset off if the
+ line number for the current expression/statement has not
+ already been set. If it has been set, the call has no effect.
+
+ The line number is reset in the following cases:
+ - when entering a new scope
+ - on each statement
+ - on each expression that start a new line
+ - before the "except" clause
+ - before the "for" and "while" expressions
+*/
+
+static void
+compiler_set_lineno(struct compiler *c, int off)
+{
+ basicblock *b;
+ if (c->u->u_lineno_set)
+ return;
+ c->u->u_lineno_set = true;
+ b = c->u->u_curblock;
+ b->b_instr[off].i_lineno = c->u->u_lineno;
+}
+
+static int
+opcode_stack_effect(int opcode, int oparg)
+{
+ switch (opcode) {
+ case POP_TOP:
+ return -1;
+ case ROT_TWO:
+ case ROT_THREE:
+ return 0;
+ case DUP_TOP:
+ return 1;
+ case ROT_FOUR:
+ return 0;
+
+ case UNARY_POSITIVE:
+ case UNARY_NEGATIVE:
+ case UNARY_NOT:
+ case UNARY_CONVERT:
+ case UNARY_INVERT:
+ return 0;
+
+ case SET_ADD:
+ case LIST_APPEND:
+ return -1;
+
+ case MAP_ADD:
+ return -2;
+
+ case BINARY_POWER:
+ case BINARY_MULTIPLY:
+ case BINARY_DIVIDE:
+ case BINARY_MODULO:
+ case BINARY_ADD:
+ case BINARY_SUBTRACT:
+ case BINARY_SUBSCR:
+ case BINARY_FLOOR_DIVIDE:
+ case BINARY_TRUE_DIVIDE:
+ return -1;
+ case INPLACE_FLOOR_DIVIDE:
+ case INPLACE_TRUE_DIVIDE:
+ return -1;
+
+ case SLICE+0:
+ return 0;
+ case SLICE+1:
+ return -1;
+ case SLICE+2:
+ return -1;
+ case SLICE+3:
+ return -2;
+
+ case STORE_SLICE+0:
+ return -2;
+ case STORE_SLICE+1:
+ return -3;
+ case STORE_SLICE+2:
+ return -3;
+ case STORE_SLICE+3:
+ return -4;
+
+ case DELETE_SLICE+0:
+ return -1;
+ case DELETE_SLICE+1:
+ return -2;
+ case DELETE_SLICE+2:
+ return -2;
+ case DELETE_SLICE+3:
+ return -3;
+
+ case INPLACE_ADD:
+ case INPLACE_SUBTRACT:
+ case INPLACE_MULTIPLY:
+ case INPLACE_DIVIDE:
+ case INPLACE_MODULO:
+ return -1;
+ case STORE_SUBSCR:
+ return -3;
+ case STORE_MAP:
+ return -2;
+ case DELETE_SUBSCR:
+ return -2;
+
+ case BINARY_LSHIFT:
+ case BINARY_RSHIFT:
+ case BINARY_AND:
+ case BINARY_XOR:
+ case BINARY_OR:
+ return -1;
+ case INPLACE_POWER:
+ return -1;
+ case GET_ITER:
+ return 0;
+
+ case PRINT_EXPR:
+ return -1;
+ case PRINT_ITEM:
+ return -1;
+ case PRINT_NEWLINE:
+ return 0;
+ case PRINT_ITEM_TO:
+ return -2;
+ case PRINT_NEWLINE_TO:
+ return -1;
+ case INPLACE_LSHIFT:
+ case INPLACE_RSHIFT:
+ case INPLACE_AND:
+ case INPLACE_XOR:
+ case INPLACE_OR:
+ return -1;
+ case BREAK_LOOP:
+ return 0;
+ case SETUP_WITH:
+ return 4;
+ case WITH_CLEANUP:
+ return -1; /* XXX Sometimes more */
+ case LOAD_LOCALS:
+ return 1;
+ case RETURN_VALUE:
+ return -1;
+ case IMPORT_STAR:
+ return -1;
+ case EXEC_STMT:
+ return -3;
+ case YIELD_VALUE:
+ return 0;
+
+ case POP_BLOCK:
+ return 0;
+ case END_FINALLY:
+ return -3; /* or -1 or -2 if no exception occurred or
+ return/break/continue */
+ case BUILD_CLASS:
+ return -2;
+
+ case STORE_NAME:
+ return -1;
+ case DELETE_NAME:
+ return 0;
+ case UNPACK_SEQUENCE:
+ return oparg-1;
+ case FOR_ITER:
+ return 1; /* or -1, at end of iterator */
+
+ case STORE_ATTR:
+ return -2;
+ case DELETE_ATTR:
+ return -1;
+ case STORE_GLOBAL:
+ return -1;
+ case DELETE_GLOBAL:
+ return 0;
+ case DUP_TOPX:
+ return oparg;
+ case LOAD_CONST:
+ return 1;
+ case LOAD_NAME:
+ return 1;
+ case BUILD_TUPLE:
+ case BUILD_LIST:
+ case BUILD_SET:
+ return 1-oparg;
+ case BUILD_MAP:
+ return 1;
+ case LOAD_ATTR:
+ return 0;
+ case COMPARE_OP:
+ return -1;
+ case IMPORT_NAME:
+ return -1;
+ case IMPORT_FROM:
+ return 1;
+
+ case JUMP_FORWARD:
+ case JUMP_IF_TRUE_OR_POP: /* -1 if jump not taken */
+ case JUMP_IF_FALSE_OR_POP: /* "" */
+ case JUMP_ABSOLUTE:
+ return 0;
+
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE:
+ return -1;
+
+ case LOAD_GLOBAL:
+ return 1;
+
+ case CONTINUE_LOOP:
+ return 0;
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ return 0;
+
+ case LOAD_FAST:
+ return 1;
+ case STORE_FAST:
+ return -1;
+ case DELETE_FAST:
+ return 0;
+
+ case RAISE_VARARGS:
+ return -oparg;
+#define NARGS(o) (((o) % 256) + 2*((o) / 256))
+ case CALL_FUNCTION:
+ return -NARGS(oparg);
+ case CALL_FUNCTION_VAR:
+ case CALL_FUNCTION_KW:
+ return -NARGS(oparg)-1;
+ case CALL_FUNCTION_VAR_KW:
+ return -NARGS(oparg)-2;
+#undef NARGS
+ case MAKE_FUNCTION:
+ return -oparg;
+ case BUILD_SLICE:
+ if (oparg == 3)
+ return -2;
+ else
+ return -1;
+
+ case MAKE_CLOSURE:
+ return -oparg-1;
+ case LOAD_CLOSURE:
+ return 1;
+ case LOAD_DEREF:
+ return 1;
+ case STORE_DEREF:
+ return -1;
+ default:
+ fprintf(stderr, "opcode = %d\n", opcode);
+ Py_FatalError("opcode_stack_effect()");
+
+ }
+ return 0; /* not reachable */
+}
+
+/* Add an opcode with no argument.
+ Returns 0 on failure, 1 on success.
+*/
+
+static int
+compiler_addop(struct compiler *c, int opcode)
+{
+ basicblock *b;
+ struct instr *i;
+ int off;
+ off = compiler_next_instr(c, c->u->u_curblock);
+ if (off < 0)
+ return 0;
+ b = c->u->u_curblock;
+ i = &b->b_instr[off];
+ i->i_opcode = opcode;
+ i->i_hasarg = 0;
+ if (opcode == RETURN_VALUE)
+ b->b_return = 1;
+ compiler_set_lineno(c, off);
+ return 1;
+}
+
+static int
+compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
+{
+ PyObject *t, *v;
+ Py_ssize_t arg;
+
+ t = _PyCode_ConstantKey(o);
+ if (t == NULL)
+ return -1;
+
+ v = PyDict_GetItem(dict, t);
+ if (!v) {
+ arg = PyDict_Size(dict);
+ v = PyInt_FromLong(arg);
+ if (!v) {
+ Py_DECREF(t);
+ return -1;
+ }
+ if (PyDict_SetItem(dict, t, v) < 0) {
+ Py_DECREF(t);
+ Py_DECREF(v);
+ return -1;
+ }
+ Py_DECREF(v);
+ }
+ else
+ arg = PyInt_AsLong(v);
+ Py_DECREF(t);
+ return arg;
+}
+
+static int
+compiler_addop_o(struct compiler *c, int opcode, PyObject *dict,
+ PyObject *o)
+{
+ int arg = compiler_add_o(c, dict, o);
+ if (arg < 0)
+ return 0;
+ return compiler_addop_i(c, opcode, arg);
+}
+
+static int
+compiler_addop_name(struct compiler *c, int opcode, PyObject *dict,
+ PyObject *o)
+{
+ int arg;
+ PyObject *mangled = _Py_Mangle(c->u->u_private, o);
+ if (!mangled)
+ return 0;
+ arg = compiler_add_o(c, dict, mangled);
+ Py_DECREF(mangled);
+ if (arg < 0)
+ return 0;
+ return compiler_addop_i(c, opcode, arg);
+}
+
+/* Add an opcode with an integer argument.
+ Returns 0 on failure, 1 on success.
+*/
+
+static int
+compiler_addop_i(struct compiler *c, int opcode, int oparg)
+{
+ struct instr *i;
+ int off;
+ off = compiler_next_instr(c, c->u->u_curblock);
+ if (off < 0)
+ return 0;
+ i = &c->u->u_curblock->b_instr[off];
+ i->i_opcode = opcode;
+ i->i_oparg = oparg;
+ i->i_hasarg = 1;
+ compiler_set_lineno(c, off);
+ return 1;
+}
+
+static int
+compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
+{
+ struct instr *i;
+ int off;
+
+ assert(b != NULL);
+ off = compiler_next_instr(c, c->u->u_curblock);
+ if (off < 0)
+ return 0;
+ i = &c->u->u_curblock->b_instr[off];
+ i->i_opcode = opcode;
+ i->i_target = b;
+ i->i_hasarg = 1;
+ if (absolute)
+ i->i_jabs = 1;
+ else
+ i->i_jrel = 1;
+ compiler_set_lineno(c, off);
+ return 1;
+}
+
+/* The distinction between NEW_BLOCK and NEXT_BLOCK is subtle. (I'd
+ like to find better names.) NEW_BLOCK() creates a new block and sets
+ it as the current block. NEXT_BLOCK() also creates an implicit jump
+ from the current block to the new block.
+*/
+
+/* The returns inside these macros make it impossible to decref objects
+ created in the local function. Local objects should use the arena.
+*/
+
+
+#define NEW_BLOCK(C) { \
+ if (compiler_use_new_block((C)) == NULL) \
+ return 0; \
+}
+
+#define NEXT_BLOCK(C) { \
+ if (compiler_next_block((C)) == NULL) \
+ return 0; \
+}
+
+#define ADDOP(C, OP) { \
+ if (!compiler_addop((C), (OP))) \
+ return 0; \
+}
+
+#define ADDOP_IN_SCOPE(C, OP) { \
+ if (!compiler_addop((C), (OP))) { \
+ compiler_exit_scope(c); \
+ return 0; \
+ } \
+}
+
+#define ADDOP_O(C, OP, O, TYPE) { \
+ if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \
+ return 0; \
+}
+
+/* Same as ADDOP_O, but steals a reference. */
+#define ADDOP_N(C, OP, O, TYPE) { \
+ if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \
+ Py_DECREF((O)); \
+ return 0; \
+ } \
+ Py_DECREF((O)); \
+}
+
+#define ADDOP_NAME(C, OP, O, TYPE) { \
+ if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \
+ return 0; \
+}
+
+#define ADDOP_I(C, OP, O) { \
+ if (!compiler_addop_i((C), (OP), (O))) \
+ return 0; \
+}
+
+#define ADDOP_JABS(C, OP, O) { \
+ if (!compiler_addop_j((C), (OP), (O), 1)) \
+ return 0; \
+}
+
+#define ADDOP_JREL(C, OP, O) { \
+ if (!compiler_addop_j((C), (OP), (O), 0)) \
+ return 0; \
+}
+
+/* VISIT and VISIT_SEQ takes an ASDL type as their second argument. They use
+ the ASDL name to synthesize the name of the C type and the visit function.
+*/
+
+#define VISIT(C, TYPE, V) {\
+ if (!compiler_visit_ ## TYPE((C), (V))) \
+ return 0; \
+}
+
+#define VISIT_IN_SCOPE(C, TYPE, V) {\
+ if (!compiler_visit_ ## TYPE((C), (V))) { \
+ compiler_exit_scope(c); \
+ return 0; \
+ } \
+}
+
+#define VISIT_SLICE(C, V, CTX) {\
+ if (!compiler_visit_slice((C), (V), (CTX))) \
+ return 0; \
+}
+
+#define VISIT_SEQ(C, TYPE, SEQ) { \
+ int _i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \
+ if (!compiler_visit_ ## TYPE((C), elt)) \
+ return 0; \
+ } \
+}
+
+#define VISIT_SEQ_IN_SCOPE(C, TYPE, SEQ) { \
+ int _i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \
+ if (!compiler_visit_ ## TYPE((C), elt)) { \
+ compiler_exit_scope(c); \
+ return 0; \
+ } \
+ } \
+}
+
+static int
+compiler_isdocstring(stmt_ty s)
+{
+ if (s->kind != Expr_kind)
+ return 0;
+ return s->v.Expr.value->kind == Str_kind;
+}
+
+/* Compile a sequence of statements, checking for a docstring. */
+
+static int
+compiler_body(struct compiler *c, asdl_seq *stmts)
+{
+ int i = 0;
+ stmt_ty st;
+
+ if (!asdl_seq_LEN(stmts))
+ return 1;
+ st = (stmt_ty)asdl_seq_GET(stmts, 0);
+ if (compiler_isdocstring(st) && Py_OptimizeFlag < 2) {
+ /* don't generate docstrings if -OO */
+ i = 1;
+ VISIT(c, expr, st->v.Expr.value);
+ if (!compiler_nameop(c, __doc__, Store))
+ return 0;
+ }
+ for (; i < asdl_seq_LEN(stmts); i++)
+ VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i));
+ return 1;
+}
+
+static PyCodeObject *
+compiler_mod(struct compiler *c, mod_ty mod)
+{
+ PyCodeObject *co;
+ int addNone = 1;
+ static PyObject *module;
+ if (!module) {
+ module = PyString_InternFromString("<module>");
+ if (!module)
+ return NULL;
+ }
+ /* Use 0 for firstlineno initially, will fixup in assemble(). */
+ if (!compiler_enter_scope(c, module, mod, 0))
+ return NULL;
+ switch (mod->kind) {
+ case Module_kind:
+ if (!compiler_body(c, mod->v.Module.body)) {
+ compiler_exit_scope(c);
+ return 0;
+ }
+ break;
+ case Interactive_kind:
+ c->c_interactive = 1;
+ VISIT_SEQ_IN_SCOPE(c, stmt,
+ mod->v.Interactive.body);
+ break;
+ case Expression_kind:
+ VISIT_IN_SCOPE(c, expr, mod->v.Expression.body);
+ addNone = 0;
+ break;
+ case Suite_kind:
+ PyErr_SetString(PyExc_SystemError,
+ "suite should not be possible");
+ return 0;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "module kind %d should not be possible",
+ mod->kind);
+ return 0;
+ }
+ co = assemble(c, addNone);
+ compiler_exit_scope(c);
+ return co;
+}
+
+/* The test for LOCAL must come before the test for FREE in order to
+ handle classes where name is both local and free. The local var is
+ a method and the free var is a free var referenced within a method.
+*/
+
+static int
+get_ref_type(struct compiler *c, PyObject *name)
+{
+ int scope = PyST_GetScope(c->u->u_ste, name);
+ if (scope == 0) {
+ char buf[350];
+ PyOS_snprintf(buf, sizeof(buf),
+ "unknown scope for %.100s in %.100s(%s) in %s\n"
+ "symbols: %s\nlocals: %s\nglobals: %s",
+ PyString_AS_STRING(name),
+ PyString_AS_STRING(c->u->u_name),
+ PyString_AS_STRING(PyObject_Repr(c->u->u_ste->ste_id)),
+ c->c_filename,
+ PyString_AS_STRING(PyObject_Repr(c->u->u_ste->ste_symbols)),
+ PyString_AS_STRING(PyObject_Repr(c->u->u_varnames)),
+ PyString_AS_STRING(PyObject_Repr(c->u->u_names))
+ );
+ Py_FatalError(buf);
+ }
+
+ return scope;
+}
+
+static int
+compiler_lookup_arg(PyObject *dict, PyObject *name)
+{
+ PyObject *k, *v;
+ k = _PyCode_ConstantKey(name);
+ if (k == NULL)
+ return -1;
+ v = PyDict_GetItem(dict, k);
+ Py_DECREF(k);
+ if (v == NULL)
+ return -1;
+ return PyInt_AS_LONG(v);
+}
+
+static int
+compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
+{
+ int i, free = PyCode_GetNumFree(co);
+ if (free == 0) {
+ ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+ ADDOP_I(c, MAKE_FUNCTION, args);
+ return 1;
+ }
+ for (i = 0; i < free; ++i) {
+ /* Bypass com_addop_varname because it will generate
+ LOAD_DEREF but LOAD_CLOSURE is needed.
+ */
+ PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
+ int arg, reftype;
+
+ /* Special case: If a class contains a method with a
+ free variable that has the same name as a method,
+ the name will be considered free *and* local in the
+ class. It should be handled by the closure, as
+ well as by the normal name loookup logic.
+ */
+ reftype = get_ref_type(c, name);
+ if (reftype == CELL)
+ arg = compiler_lookup_arg(c->u->u_cellvars, name);
+ else /* (reftype == FREE) */
+ arg = compiler_lookup_arg(c->u->u_freevars, name);
+ if (arg == -1) {
+ printf("lookup %s in %s %d %d\n"
+ "freevars of %s: %s\n",
+ PyString_AS_STRING(PyObject_Repr(name)),
+ PyString_AS_STRING(c->u->u_name),
+ reftype, arg,
+ PyString_AS_STRING(co->co_name),
+ PyString_AS_STRING(PyObject_Repr(co->co_freevars)));
+ Py_FatalError("compiler_make_closure()");
+ }
+ ADDOP_I(c, LOAD_CLOSURE, arg);
+ }
+ ADDOP_I(c, BUILD_TUPLE, free);
+ ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+ ADDOP_I(c, MAKE_CLOSURE, args);
+ return 1;
+}
+
+static int
+compiler_decorators(struct compiler *c, asdl_seq* decos)
+{
+ int i;
+
+ if (!decos)
+ return 1;
+
+ for (i = 0; i < asdl_seq_LEN(decos); i++) {
+ VISIT(c, expr, (expr_ty)asdl_seq_GET(decos, i));
+ }
+ return 1;
+}
+
+static int
+compiler_arguments(struct compiler *c, arguments_ty args)
+{
+ int i;
+ int n = asdl_seq_LEN(args->args);
+ /* Correctly handle nested argument lists */
+ for (i = 0; i < n; i++) {
+ expr_ty arg = (expr_ty)asdl_seq_GET(args->args, i);
+ if (arg->kind == Tuple_kind) {
+ PyObject *id = PyString_FromFormat(".%d", i);
+ if (id == NULL) {
+ return 0;
+ }
+ if (!compiler_nameop(c, id, Load)) {
+ Py_DECREF(id);
+ return 0;
+ }
+ Py_DECREF(id);
+ VISIT(c, expr, arg);
+ }
+ }
+ return 1;
+}
+
+static int
+compiler_function(struct compiler *c, stmt_ty s)
+{
+ PyCodeObject *co;
+ PyObject *first_const = Py_None;
+ arguments_ty args = s->v.FunctionDef.args;
+ asdl_seq* decos = s->v.FunctionDef.decorator_list;
+ stmt_ty st;
+ int i, n, docstring;
+
+ assert(s->kind == FunctionDef_kind);
+
+ if (!compiler_decorators(c, decos))
+ return 0;
+ if (args->defaults)
+ VISIT_SEQ(c, expr, args->defaults);
+ if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s,
+ s->lineno))
+ return 0;
+
+ st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, 0);
+ docstring = compiler_isdocstring(st);
+ if (docstring && Py_OptimizeFlag < 2)
+ first_const = st->v.Expr.value->v.Str.s;
+ if (compiler_add_o(c, c->u->u_consts, first_const) < 0) {
+ compiler_exit_scope(c);
+ return 0;
+ }
+
+ /* unpack nested arguments */
+ compiler_arguments(c, args);
+
+ c->u->u_argcount = asdl_seq_LEN(args->args);
+ n = asdl_seq_LEN(s->v.FunctionDef.body);
+ /* if there was a docstring, we need to skip the first statement */
+ for (i = docstring; i < n; i++) {
+ st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, i);
+ VISIT_IN_SCOPE(c, stmt, st);
+ }
+ co = assemble(c, 1);
+ compiler_exit_scope(c);
+ if (co == NULL)
+ return 0;
+
+ compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
+ Py_DECREF(co);
+
+ for (i = 0; i < asdl_seq_LEN(decos); i++) {
+ ADDOP_I(c, CALL_FUNCTION, 1);
+ }
+
+ return compiler_nameop(c, s->v.FunctionDef.name, Store);
+}
+
+static int
+compiler_class(struct compiler *c, stmt_ty s)
+{
+ int n, i;
+ PyCodeObject *co;
+ PyObject *str;
+ asdl_seq* decos = s->v.ClassDef.decorator_list;
+
+ if (!compiler_decorators(c, decos))
+ return 0;
+
+ /* push class name on stack, needed by BUILD_CLASS */
+ ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts);
+ /* push the tuple of base classes on the stack */
+ n = asdl_seq_LEN(s->v.ClassDef.bases);
+ if (n > 0)
+ VISIT_SEQ(c, expr, s->v.ClassDef.bases);
+ ADDOP_I(c, BUILD_TUPLE, n);
+ if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s,
+ s->lineno))
+ return 0;
+ Py_INCREF(s->v.ClassDef.name);
+ Py_XSETREF(c->u->u_private, s->v.ClassDef.name);
+ str = PyString_InternFromString("__name__");
+ if (!str || !compiler_nameop(c, str, Load)) {
+ Py_XDECREF(str);
+ compiler_exit_scope(c);
+ return 0;
+ }
+
+ Py_DECREF(str);
+ str = PyString_InternFromString("__module__");
+ if (!str || !compiler_nameop(c, str, Store)) {
+ Py_XDECREF(str);
+ compiler_exit_scope(c);
+ return 0;
+ }
+ Py_DECREF(str);
+
+ if (!compiler_body(c, s->v.ClassDef.body)) {
+ compiler_exit_scope(c);
+ return 0;
+ }
+
+ ADDOP_IN_SCOPE(c, LOAD_LOCALS);
+ ADDOP_IN_SCOPE(c, RETURN_VALUE);
+ co = assemble(c, 1);
+ compiler_exit_scope(c);
+ if (co == NULL)
+ return 0;
+
+ compiler_make_closure(c, co, 0);
+ Py_DECREF(co);
+
+ ADDOP_I(c, CALL_FUNCTION, 0);
+ ADDOP(c, BUILD_CLASS);
+ /* apply decorators */
+ for (i = 0; i < asdl_seq_LEN(decos); i++) {
+ ADDOP_I(c, CALL_FUNCTION, 1);
+ }
+ if (!compiler_nameop(c, s->v.ClassDef.name, Store))
+ return 0;
+ return 1;
+}
+
+static int
+compiler_ifexp(struct compiler *c, expr_ty e)
+{
+ basicblock *end, *next;
+
+ assert(e->kind == IfExp_kind);
+ end = compiler_new_block(c);
+ if (end == NULL)
+ return 0;
+ next = compiler_new_block(c);
+ if (next == NULL)
+ return 0;
+ VISIT(c, expr, e->v.IfExp.test);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
+ VISIT(c, expr, e->v.IfExp.body);
+ ADDOP_JREL(c, JUMP_FORWARD, end);
+ compiler_use_next_block(c, next);
+ VISIT(c, expr, e->v.IfExp.orelse);
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_lambda(struct compiler *c, expr_ty e)
+{
+ PyCodeObject *co;
+ static identifier name;
+ arguments_ty args = e->v.Lambda.args;
+ assert(e->kind == Lambda_kind);
+
+ if (!name) {
+ name = PyString_InternFromString("<lambda>");
+ if (!name)
+ return 0;
+ }
+
+ if (args->defaults)
+ VISIT_SEQ(c, expr, args->defaults);
+ if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
+ return 0;
+
+ /* unpack nested arguments */
+ compiler_arguments(c, args);
+
+ /* Make None the first constant, so the lambda can't have a
+ docstring. */
+ if (compiler_add_o(c, c->u->u_consts, Py_None) < 0)
+ return 0;
+
+ c->u->u_argcount = asdl_seq_LEN(args->args);
+ VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
+ if (c->u->u_ste->ste_generator) {
+ ADDOP_IN_SCOPE(c, POP_TOP);
+ }
+ else {
+ ADDOP_IN_SCOPE(c, RETURN_VALUE);
+ }
+ co = assemble(c, 1);
+ compiler_exit_scope(c);
+ if (co == NULL)
+ return 0;
+
+ compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
+ Py_DECREF(co);
+
+ return 1;
+}
+
+static int
+compiler_print(struct compiler *c, stmt_ty s)
+{
+ int i, n;
+ bool dest;
+
+ assert(s->kind == Print_kind);
+ n = asdl_seq_LEN(s->v.Print.values);
+ dest = false;
+ if (s->v.Print.dest) {
+ VISIT(c, expr, s->v.Print.dest);
+ dest = true;
+ }
+ for (i = 0; i < n; i++) {
+ expr_ty e = (expr_ty)asdl_seq_GET(s->v.Print.values, i);
+ if (dest) {
+ ADDOP(c, DUP_TOP);
+ VISIT(c, expr, e);
+ ADDOP(c, ROT_TWO);
+ ADDOP(c, PRINT_ITEM_TO);
+ }
+ else {
+ VISIT(c, expr, e);
+ ADDOP(c, PRINT_ITEM);
+ }
+ }
+ if (s->v.Print.nl) {
+ if (dest)
+ ADDOP(c, PRINT_NEWLINE_TO)
+ else
+ ADDOP(c, PRINT_NEWLINE)
+ }
+ else if (dest)
+ ADDOP(c, POP_TOP);
+ return 1;
+}
+
+static int
+compiler_if(struct compiler *c, stmt_ty s)
+{
+ basicblock *end, *next;
+ int constant;
+ assert(s->kind == If_kind);
+ end = compiler_new_block(c);
+ if (end == NULL)
+ return 0;
+
+ constant = expr_constant(s->v.If.test);
+ /* constant = 0: "if 0"
+ * constant = 1: "if 1", "if 2", ...
+ * constant = -1: rest */
+ if (constant == 0) {
+ if (s->v.If.orelse)
+ VISIT_SEQ(c, stmt, s->v.If.orelse);
+ } else if (constant == 1) {
+ VISIT_SEQ(c, stmt, s->v.If.body);
+ } else {
+ if (s->v.If.orelse) {
+ next = compiler_new_block(c);
+ if (next == NULL)
+ return 0;
+ }
+ else
+ next = end;
+ VISIT(c, expr, s->v.If.test);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
+ VISIT_SEQ(c, stmt, s->v.If.body);
+ ADDOP_JREL(c, JUMP_FORWARD, end);
+ if (s->v.If.orelse) {
+ compiler_use_next_block(c, next);
+ VISIT_SEQ(c, stmt, s->v.If.orelse);
+ }
+ }
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_for(struct compiler *c, stmt_ty s)
+{
+ basicblock *start, *cleanup, *end;
+
+ start = compiler_new_block(c);
+ cleanup = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (start == NULL || end == NULL || cleanup == NULL)
+ return 0;
+ ADDOP_JREL(c, SETUP_LOOP, end);
+ if (!compiler_push_fblock(c, LOOP, start))
+ return 0;
+ VISIT(c, expr, s->v.For.iter);
+ ADDOP(c, GET_ITER);
+ compiler_use_next_block(c, start);
+ ADDOP_JREL(c, FOR_ITER, cleanup);
+ VISIT(c, expr, s->v.For.target);
+ VISIT_SEQ(c, stmt, s->v.For.body);
+ ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+ compiler_use_next_block(c, cleanup);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, LOOP, start);
+ VISIT_SEQ(c, stmt, s->v.For.orelse);
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_while(struct compiler *c, stmt_ty s)
+{
+ basicblock *loop, *orelse, *end, *anchor = NULL;
+ int constant = expr_constant(s->v.While.test);
+
+ if (constant == 0) {
+ if (s->v.While.orelse)
+ VISIT_SEQ(c, stmt, s->v.While.orelse);
+ return 1;
+ }
+ loop = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (constant == -1) {
+ anchor = compiler_new_block(c);
+ if (anchor == NULL)
+ return 0;
+ }
+ if (loop == NULL || end == NULL)
+ return 0;
+ if (s->v.While.orelse) {
+ orelse = compiler_new_block(c);
+ if (orelse == NULL)
+ return 0;
+ }
+ else
+ orelse = NULL;
+
+ ADDOP_JREL(c, SETUP_LOOP, end);
+ compiler_use_next_block(c, loop);
+ if (!compiler_push_fblock(c, LOOP, loop))
+ return 0;
+ if (constant == -1) {
+ VISIT(c, expr, s->v.While.test);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor);
+ }
+ VISIT_SEQ(c, stmt, s->v.While.body);
+ ADDOP_JABS(c, JUMP_ABSOLUTE, loop);
+
+ /* XXX should the two POP instructions be in a separate block
+ if there is no else clause ?
+ */
+
+ if (constant == -1)
+ compiler_use_next_block(c, anchor);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, LOOP, loop);
+ if (orelse != NULL) /* what if orelse is just pass? */
+ VISIT_SEQ(c, stmt, s->v.While.orelse);
+ compiler_use_next_block(c, end);
+
+ return 1;
+}
+
+static int
+compiler_continue(struct compiler *c)
+{
+ static const char LOOP_ERROR_MSG[] = "'continue' not properly in loop";
+ static const char IN_FINALLY_ERROR_MSG[] =
+ "'continue' not supported inside 'finally' clause";
+ int i;
+
+ if (!c->u->u_nfblocks)
+ return compiler_error(c, LOOP_ERROR_MSG);
+ i = c->u->u_nfblocks - 1;
+ switch (c->u->u_fblock[i].fb_type) {
+ case LOOP:
+ ADDOP_JABS(c, JUMP_ABSOLUTE, c->u->u_fblock[i].fb_block);
+ break;
+ case EXCEPT:
+ case FINALLY_TRY:
+ while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP) {
+ /* Prevent continue anywhere under a finally
+ even if hidden in a sub-try or except. */
+ if (c->u->u_fblock[i].fb_type == FINALLY_END)
+ return compiler_error(c, IN_FINALLY_ERROR_MSG);
+ }
+ if (i == -1)
+ return compiler_error(c, LOOP_ERROR_MSG);
+ ADDOP_JABS(c, CONTINUE_LOOP, c->u->u_fblock[i].fb_block);
+ break;
+ case FINALLY_END:
+ return compiler_error(c, IN_FINALLY_ERROR_MSG);
+ }
+
+ return 1;
+}
+
+/* Code generated for "try: <body> finally: <finalbody>" is as follows:
+
+ SETUP_FINALLY L
+ <code for body>
+ POP_BLOCK
+ LOAD_CONST <None>
+ L: <code for finalbody>
+ END_FINALLY
+
+ The special instructions use the block stack. Each block
+ stack entry contains the instruction that created it (here
+ SETUP_FINALLY), the level of the value stack at the time the
+ block stack entry was created, and a label (here L).
+
+ SETUP_FINALLY:
+ Pushes the current value stack level and the label
+ onto the block stack.
+ POP_BLOCK:
+ Pops en entry from the block stack, and pops the value
+ stack until its level is the same as indicated on the
+ block stack. (The label is ignored.)
+ END_FINALLY:
+ Pops a variable number of entries from the *value* stack
+ and re-raises the exception they specify. The number of
+ entries popped depends on the (pseudo) exception type.
+
+ The block stack is unwound when an exception is raised:
+ when a SETUP_FINALLY entry is found, the exception is pushed
+ onto the value stack (and the exception condition is cleared),
+ and the interpreter jumps to the label gotten from the block
+ stack.
+*/
+
+static int
+compiler_try_finally(struct compiler *c, stmt_ty s)
+{
+ basicblock *body, *end;
+ body = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (body == NULL || end == NULL)
+ return 0;
+
+ ADDOP_JREL(c, SETUP_FINALLY, end);
+ compiler_use_next_block(c, body);
+ if (!compiler_push_fblock(c, FINALLY_TRY, body))
+ return 0;
+ VISIT_SEQ(c, stmt, s->v.TryFinally.body);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, FINALLY_TRY, body);
+
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ compiler_use_next_block(c, end);
+ if (!compiler_push_fblock(c, FINALLY_END, end))
+ return 0;
+ VISIT_SEQ(c, stmt, s->v.TryFinally.finalbody);
+ ADDOP(c, END_FINALLY);
+ compiler_pop_fblock(c, FINALLY_END, end);
+
+ return 1;
+}
+
+/*
+ Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...":
+ (The contents of the value stack is shown in [], with the top
+ at the right; 'tb' is trace-back info, 'val' the exception's
+ associated value, and 'exc' the exception.)
+
+ Value stack Label Instruction Argument
+ [] SETUP_EXCEPT L1
+ [] <code for S>
+ [] POP_BLOCK
+ [] JUMP_FORWARD L0
+
+ [tb, val, exc] L1: DUP )
+ [tb, val, exc, exc] <evaluate E1> )
+ [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1
+ [tb, val, exc, 1-or-0] POP_JUMP_IF_FALSE L2 )
+ [tb, val, exc] POP
+ [tb, val] <assign to V1> (or POP if no V1)
+ [tb] POP
+ [] <code for S1>
+ JUMP_FORWARD L0
+
+ [tb, val, exc] L2: DUP
+ .............................etc.......................
+
+ [tb, val, exc] Ln+1: END_FINALLY # re-raise exception
+
+ [] L0: <next statement>
+
+ Of course, parts are not generated if Vi or Ei is not present.
+*/
+static int
+compiler_try_except(struct compiler *c, stmt_ty s)
+{
+ basicblock *body, *orelse, *except, *end;
+ int i, n;
+
+ body = compiler_new_block(c);
+ except = compiler_new_block(c);
+ orelse = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (body == NULL || except == NULL || orelse == NULL || end == NULL)
+ return 0;
+ ADDOP_JREL(c, SETUP_EXCEPT, except);
+ compiler_use_next_block(c, body);
+ if (!compiler_push_fblock(c, EXCEPT, body))
+ return 0;
+ VISIT_SEQ(c, stmt, s->v.TryExcept.body);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, EXCEPT, body);
+ ADDOP_JREL(c, JUMP_FORWARD, orelse);
+ n = asdl_seq_LEN(s->v.TryExcept.handlers);
+ compiler_use_next_block(c, except);
+ for (i = 0; i < n; i++) {
+ excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
+ s->v.TryExcept.handlers, i);
+ if (!handler->v.ExceptHandler.type && i < n-1)
+ return compiler_error(c, "default 'except:' must be last");
+ c->u->u_lineno_set = false;
+ c->u->u_lineno = handler->lineno;
+ except = compiler_new_block(c);
+ if (except == NULL)
+ return 0;
+ if (handler->v.ExceptHandler.type) {
+ ADDOP(c, DUP_TOP);
+ VISIT(c, expr, handler->v.ExceptHandler.type);
+ ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, except);
+ }
+ ADDOP(c, POP_TOP);
+ if (handler->v.ExceptHandler.name) {
+ VISIT(c, expr, handler->v.ExceptHandler.name);
+ }
+ else {
+ ADDOP(c, POP_TOP);
+ }
+ ADDOP(c, POP_TOP);
+ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
+ ADDOP_JREL(c, JUMP_FORWARD, end);
+ compiler_use_next_block(c, except);
+ }
+ ADDOP(c, END_FINALLY);
+ compiler_use_next_block(c, orelse);
+ VISIT_SEQ(c, stmt, s->v.TryExcept.orelse);
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_import_as(struct compiler *c, identifier name, identifier asname)
+{
+ /* The IMPORT_NAME opcode was already generated. This function
+ merely needs to bind the result to a name.
+
+ If there is a dot in name, we need to split it and emit a
+ LOAD_ATTR for each name.
+ */
+ const char *src = PyString_AS_STRING(name);
+ const char *dot = strchr(src, '.');
+ if (dot) {
+ /* Consume the base module name to get the first attribute */
+ src = dot + 1;
+ while (dot) {
+ /* NB src is only defined when dot != NULL */
+ PyObject *attr;
+ dot = strchr(src, '.');
+ attr = PyString_FromStringAndSize(src,
+ dot ? dot - src : strlen(src));
+ if (!attr)
+ return 0;
+ ADDOP_N(c, LOAD_ATTR, attr, names);
+ src = dot + 1;
+ }
+ }
+ return compiler_nameop(c, asname, Store);
+}
+
+static int
+compiler_import(struct compiler *c, stmt_ty s)
+{
+ /* The Import node stores a module name like a.b.c as a single
+ string. This is convenient for all cases except
+ import a.b.c as d
+ where we need to parse that string to extract the individual
+ module names.
+ XXX Perhaps change the representation to make this case simpler?
+ */
+ int i, n = asdl_seq_LEN(s->v.Import.names);
+
+ for (i = 0; i < n; i++) {
+ alias_ty alias = (alias_ty)asdl_seq_GET(s->v.Import.names, i);
+ int r;
+ PyObject *level;
+
+ if (c->c_flags && (c->c_flags->cf_flags & CO_FUTURE_ABSOLUTE_IMPORT))
+ level = PyInt_FromLong(0);
+ else
+ level = PyInt_FromLong(-1);
+
+ if (level == NULL)
+ return 0;
+
+ ADDOP_N(c, LOAD_CONST, level, consts);
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP_NAME(c, IMPORT_NAME, alias->name, names);
+
+ if (alias->asname) {
+ r = compiler_import_as(c, alias->name, alias->asname);
+ if (!r)
+ return r;
+ }
+ else {
+ identifier tmp = alias->name;
+ const char *base = PyString_AS_STRING(alias->name);
+ char *dot = strchr(base, '.');
+ if (dot) {
+ tmp = PyString_FromStringAndSize(base,
+ dot - base);
+ if (tmp == NULL)
+ return 0;
+ }
+ r = compiler_nameop(c, tmp, Store);
+ if (dot) {
+ Py_DECREF(tmp);
+ }
+ if (!r)
+ return r;
+ }
+ }
+ return 1;
+}
+
+static int
+compiler_from_import(struct compiler *c, stmt_ty s)
+{
+ int i, n = asdl_seq_LEN(s->v.ImportFrom.names);
+
+ PyObject *level, *names;
+ static PyObject *empty_string;
+
+ if (!empty_string) {
+ empty_string = PyString_FromString("");
+ if (!empty_string)
+ return 0;
+ }
+
+ if (s->v.ImportFrom.level == 0 && c->c_flags &&
+ !(c->c_flags->cf_flags & CO_FUTURE_ABSOLUTE_IMPORT))
+ level = PyInt_FromLong(-1);
+ else
+ level = PyInt_FromLong(s->v.ImportFrom.level);
+
+ if (!level) {
+ return 0;
+ }
+ ADDOP_N(c, LOAD_CONST, level, consts);
+
+ names = PyTuple_New(n);
+ if (!names)
+ return 0;
+
+ /* build up the names */
+ for (i = 0; i < n; i++) {
+ alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i);
+ Py_INCREF(alias->name);
+ PyTuple_SET_ITEM(names, i, alias->name);
+ }
+
+ if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module &&
+ !strcmp(PyString_AS_STRING(s->v.ImportFrom.module), "__future__")) {
+ Py_DECREF(names);
+ return compiler_error(c, "from __future__ imports must occur "
+ "at the beginning of the file");
+ }
+ ADDOP_N(c, LOAD_CONST, names, consts);
+
+ if (s->v.ImportFrom.module) {
+ ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names);
+ }
+ else {
+ ADDOP_NAME(c, IMPORT_NAME, empty_string, names);
+ }
+ for (i = 0; i < n; i++) {
+ alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i);
+ identifier store_name;
+
+ if (i == 0 && *PyString_AS_STRING(alias->name) == '*') {
+ assert(n == 1);
+ ADDOP(c, IMPORT_STAR);
+ return 1;
+ }
+
+ ADDOP_NAME(c, IMPORT_FROM, alias->name, names);
+ store_name = alias->name;
+ if (alias->asname)
+ store_name = alias->asname;
+
+ if (!compiler_nameop(c, store_name, Store)) {
+ return 0;
+ }
+ }
+ /* remove imported module */
+ ADDOP(c, POP_TOP);
+ return 1;
+}
+
+static int
+compiler_assert(struct compiler *c, stmt_ty s)
+{
+ static PyObject *assertion_error = NULL;
+ basicblock *end;
+
+ if (Py_OptimizeFlag)
+ return 1;
+ if (assertion_error == NULL) {
+ assertion_error = PyString_InternFromString("AssertionError");
+ if (assertion_error == NULL)
+ return 0;
+ }
+ if (s->v.Assert.test->kind == Tuple_kind &&
+ asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) {
+ const char* msg =
+ "assertion is always true, perhaps remove parentheses?";
+ if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, c->c_filename,
+ c->u->u_lineno, NULL, NULL) == -1)
+ return 0;
+ }
+ VISIT(c, expr, s->v.Assert.test);
+ end = compiler_new_block(c);
+ if (end == NULL)
+ return 0;
+ ADDOP_JABS(c, POP_JUMP_IF_TRUE, end);
+ ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
+ if (s->v.Assert.msg) {
+ VISIT(c, expr, s->v.Assert.msg);
+ ADDOP_I(c, CALL_FUNCTION, 1);
+ }
+ ADDOP_I(c, RAISE_VARARGS, 1);
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_visit_stmt(struct compiler *c, stmt_ty s)
+{
+ int i, n;
+
+ /* Always assign a lineno to the next instruction for a stmt. */
+ c->u->u_lineno = s->lineno;
+ c->u->u_lineno_set = false;
+
+ switch (s->kind) {
+ case FunctionDef_kind:
+ return compiler_function(c, s);
+ case ClassDef_kind:
+ return compiler_class(c, s);
+ case Return_kind:
+ if (c->u->u_ste->ste_type != FunctionBlock)
+ return compiler_error(c, "'return' outside function");
+ if (s->v.Return.value) {
+ VISIT(c, expr, s->v.Return.value);
+ }
+ else
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, RETURN_VALUE);
+ break;
+ case Delete_kind:
+ VISIT_SEQ(c, expr, s->v.Delete.targets)
+ break;
+ case Assign_kind:
+ n = asdl_seq_LEN(s->v.Assign.targets);
+ VISIT(c, expr, s->v.Assign.value);
+ for (i = 0; i < n; i++) {
+ if (i < n - 1)
+ ADDOP(c, DUP_TOP);
+ VISIT(c, expr,
+ (expr_ty)asdl_seq_GET(s->v.Assign.targets, i));
+ }
+ break;
+ case AugAssign_kind:
+ return compiler_augassign(c, s);
+ case Print_kind:
+ return compiler_print(c, s);
+ case For_kind:
+ return compiler_for(c, s);
+ case While_kind:
+ return compiler_while(c, s);
+ case If_kind:
+ return compiler_if(c, s);
+ case Raise_kind:
+ n = 0;
+ if (s->v.Raise.type) {
+ VISIT(c, expr, s->v.Raise.type);
+ n++;
+ if (s->v.Raise.inst) {
+ VISIT(c, expr, s->v.Raise.inst);
+ n++;
+ if (s->v.Raise.tback) {
+ VISIT(c, expr, s->v.Raise.tback);
+ n++;
+ }
+ }
+ }
+ ADDOP_I(c, RAISE_VARARGS, n);
+ break;
+ case TryExcept_kind:
+ return compiler_try_except(c, s);
+ case TryFinally_kind:
+ return compiler_try_finally(c, s);
+ case Assert_kind:
+ return compiler_assert(c, s);
+ case Import_kind:
+ return compiler_import(c, s);
+ case ImportFrom_kind:
+ return compiler_from_import(c, s);
+ case Exec_kind:
+ VISIT(c, expr, s->v.Exec.body);
+ if (s->v.Exec.globals) {
+ VISIT(c, expr, s->v.Exec.globals);
+ if (s->v.Exec.locals) {
+ VISIT(c, expr, s->v.Exec.locals);
+ } else {
+ ADDOP(c, DUP_TOP);
+ }
+ } else {
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, DUP_TOP);
+ }
+ ADDOP(c, EXEC_STMT);
+ break;
+ case Global_kind:
+ break;
+ case Expr_kind:
+ if (c->c_interactive && c->c_nestlevel <= 1) {
+ VISIT(c, expr, s->v.Expr.value);
+ ADDOP(c, PRINT_EXPR);
+ }
+ else if (s->v.Expr.value->kind != Str_kind &&
+ s->v.Expr.value->kind != Num_kind) {
+ VISIT(c, expr, s->v.Expr.value);
+ ADDOP(c, POP_TOP);
+ }
+ break;
+ case Pass_kind:
+ break;
+ case Break_kind:
+ if (!compiler_in_loop(c))
+ return compiler_error(c, "'break' outside loop");
+ ADDOP(c, BREAK_LOOP);
+ break;
+ case Continue_kind:
+ return compiler_continue(c);
+ case With_kind:
+ return compiler_with(c, s);
+ }
+ return 1;
+}
+
+static int
+unaryop(unaryop_ty op)
+{
+ switch (op) {
+ case Invert:
+ return UNARY_INVERT;
+ case Not:
+ return UNARY_NOT;
+ case UAdd:
+ return UNARY_POSITIVE;
+ case USub:
+ return UNARY_NEGATIVE;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unary op %d should not be possible", op);
+ return 0;
+ }
+}
+
+static int
+binop(struct compiler *c, operator_ty op)
+{
+ switch (op) {
+ case Add:
+ return BINARY_ADD;
+ case Sub:
+ return BINARY_SUBTRACT;
+ case Mult:
+ return BINARY_MULTIPLY;
+ case Div:
+ if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION)
+ return BINARY_TRUE_DIVIDE;
+ else
+ return BINARY_DIVIDE;
+ case Mod:
+ return BINARY_MODULO;
+ case Pow:
+ return BINARY_POWER;
+ case LShift:
+ return BINARY_LSHIFT;
+ case RShift:
+ return BINARY_RSHIFT;
+ case BitOr:
+ return BINARY_OR;
+ case BitXor:
+ return BINARY_XOR;
+ case BitAnd:
+ return BINARY_AND;
+ case FloorDiv:
+ return BINARY_FLOOR_DIVIDE;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "binary op %d should not be possible", op);
+ return 0;
+ }
+}
+
+static int
+cmpop(cmpop_ty op)
+{
+ switch (op) {
+ case Eq:
+ return PyCmp_EQ;
+ case NotEq:
+ return PyCmp_NE;
+ case Lt:
+ return PyCmp_LT;
+ case LtE:
+ return PyCmp_LE;
+ case Gt:
+ return PyCmp_GT;
+ case GtE:
+ return PyCmp_GE;
+ case Is:
+ return PyCmp_IS;
+ case IsNot:
+ return PyCmp_IS_NOT;
+ case In:
+ return PyCmp_IN;
+ case NotIn:
+ return PyCmp_NOT_IN;
+ default:
+ return PyCmp_BAD;
+ }
+}
+
+static int
+inplace_binop(struct compiler *c, operator_ty op)
+{
+ switch (op) {
+ case Add:
+ return INPLACE_ADD;
+ case Sub:
+ return INPLACE_SUBTRACT;
+ case Mult:
+ return INPLACE_MULTIPLY;
+ case Div:
+ if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION)
+ return INPLACE_TRUE_DIVIDE;
+ else
+ return INPLACE_DIVIDE;
+ case Mod:
+ return INPLACE_MODULO;
+ case Pow:
+ return INPLACE_POWER;
+ case LShift:
+ return INPLACE_LSHIFT;
+ case RShift:
+ return INPLACE_RSHIFT;
+ case BitOr:
+ return INPLACE_OR;
+ case BitXor:
+ return INPLACE_XOR;
+ case BitAnd:
+ return INPLACE_AND;
+ case FloorDiv:
+ return INPLACE_FLOOR_DIVIDE;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "inplace binary op %d should not be possible", op);
+ return 0;
+ }
+}
+
+static int
+compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
+{
+ int op, scope, arg;
+ enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype;
+
+ PyObject *dict = c->u->u_names;
+ PyObject *mangled;
+ /* XXX AugStore isn't used anywhere! */
+
+ mangled = _Py_Mangle(c->u->u_private, name);
+ if (!mangled)
+ return 0;
+
+ op = 0;
+ optype = OP_NAME;
+ scope = PyST_GetScope(c->u->u_ste, mangled);
+ switch (scope) {
+ case FREE:
+ dict = c->u->u_freevars;
+ optype = OP_DEREF;
+ break;
+ case CELL:
+ dict = c->u->u_cellvars;
+ optype = OP_DEREF;
+ break;
+ case LOCAL:
+ if (c->u->u_ste->ste_type == FunctionBlock)
+ optype = OP_FAST;
+ break;
+ case GLOBAL_IMPLICIT:
+ if (c->u->u_ste->ste_type == FunctionBlock &&
+ !c->u->u_ste->ste_unoptimized)
+ optype = OP_GLOBAL;
+ break;
+ case GLOBAL_EXPLICIT:
+ optype = OP_GLOBAL;
+ break;
+ default:
+ /* scope can be 0 */
+ break;
+ }
+
+ /* XXX Leave assert here, but handle __doc__ and the like better */
+ assert(scope || PyString_AS_STRING(name)[0] == '_');
+
+ switch (optype) {
+ case OP_DEREF:
+ switch (ctx) {
+ case Load: op = LOAD_DEREF; break;
+ case Store: op = STORE_DEREF; break;
+ case AugLoad:
+ case AugStore:
+ break;
+ case Del:
+ PyErr_Format(PyExc_SyntaxError,
+ "can not delete variable '%s' referenced "
+ "in nested scope",
+ PyString_AS_STRING(name));
+ Py_DECREF(mangled);
+ return 0;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid for deref variable");
+ return 0;
+ }
+ break;
+ case OP_FAST:
+ switch (ctx) {
+ case Load: op = LOAD_FAST; break;
+ case Store: op = STORE_FAST; break;
+ case Del: op = DELETE_FAST; break;
+ case AugLoad:
+ case AugStore:
+ break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid for local variable");
+ return 0;
+ }
+ ADDOP_N(c, op, mangled, varnames);
+ return 1;
+ case OP_GLOBAL:
+ switch (ctx) {
+ case Load: op = LOAD_GLOBAL; break;
+ case Store: op = STORE_GLOBAL; break;
+ case Del: op = DELETE_GLOBAL; break;
+ case AugLoad:
+ case AugStore:
+ break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid for global variable");
+ return 0;
+ }
+ break;
+ case OP_NAME:
+ switch (ctx) {
+ case Load: op = LOAD_NAME; break;
+ case Store: op = STORE_NAME; break;
+ case Del: op = DELETE_NAME; break;
+ case AugLoad:
+ case AugStore:
+ break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid for name variable");
+ return 0;
+ }
+ break;
+ }
+
+ assert(op);
+ arg = compiler_add_o(c, dict, mangled);
+ Py_DECREF(mangled);
+ if (arg < 0)
+ return 0;
+ return compiler_addop_i(c, op, arg);
+}
+
+static int
+compiler_boolop(struct compiler *c, expr_ty e)
+{
+ basicblock *end;
+ int jumpi, i, n;
+ asdl_seq *s;
+
+ assert(e->kind == BoolOp_kind);
+ if (e->v.BoolOp.op == And)
+ jumpi = JUMP_IF_FALSE_OR_POP;
+ else
+ jumpi = JUMP_IF_TRUE_OR_POP;
+ end = compiler_new_block(c);
+ if (end == NULL)
+ return 0;
+ s = e->v.BoolOp.values;
+ n = asdl_seq_LEN(s) - 1;
+ assert(n >= 0);
+ for (i = 0; i < n; ++i) {
+ VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i));
+ ADDOP_JABS(c, jumpi, end);
+ }
+ VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n));
+ compiler_use_next_block(c, end);
+ return 1;
+}
+
+static int
+compiler_list(struct compiler *c, expr_ty e)
+{
+ int n = asdl_seq_LEN(e->v.List.elts);
+ if (e->v.List.ctx == Store) {
+ ADDOP_I(c, UNPACK_SEQUENCE, n);
+ }
+ VISIT_SEQ(c, expr, e->v.List.elts);
+ if (e->v.List.ctx == Load) {
+ ADDOP_I(c, BUILD_LIST, n);
+ }
+ return 1;
+}
+
+static int
+compiler_tuple(struct compiler *c, expr_ty e)
+{
+ int n = asdl_seq_LEN(e->v.Tuple.elts);
+ if (e->v.Tuple.ctx == Store) {
+ ADDOP_I(c, UNPACK_SEQUENCE, n);
+ }
+ VISIT_SEQ(c, expr, e->v.Tuple.elts);
+ if (e->v.Tuple.ctx == Load) {
+ ADDOP_I(c, BUILD_TUPLE, n);
+ }
+ return 1;
+}
+
+static int
+compiler_compare(struct compiler *c, expr_ty e)
+{
+ int i, n;
+ basicblock *cleanup = NULL;
+
+ /* XXX the logic can be cleaned up for 1 or multiple comparisons */
+ VISIT(c, expr, e->v.Compare.left);
+ n = asdl_seq_LEN(e->v.Compare.ops);
+ assert(n > 0);
+ if (n > 1) {
+ cleanup = compiler_new_block(c);
+ if (cleanup == NULL)
+ return 0;
+ VISIT(c, expr,
+ (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0));
+ }
+ for (i = 1; i < n; i++) {
+ ADDOP(c, DUP_TOP);
+ ADDOP(c, ROT_THREE);
+ ADDOP_I(c, COMPARE_OP,
+ cmpop((cmpop_ty)(asdl_seq_GET(
+ e->v.Compare.ops, i - 1))));
+ ADDOP_JABS(c, JUMP_IF_FALSE_OR_POP, cleanup);
+ NEXT_BLOCK(c);
+ if (i < (n - 1))
+ VISIT(c, expr,
+ (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i));
+ }
+ VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n - 1));
+ ADDOP_I(c, COMPARE_OP,
+ cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n - 1))));
+ if (n > 1) {
+ basicblock *end = compiler_new_block(c);
+ if (end == NULL)
+ return 0;
+ ADDOP_JREL(c, JUMP_FORWARD, end);
+ compiler_use_next_block(c, cleanup);
+ ADDOP(c, ROT_TWO);
+ ADDOP(c, POP_TOP);
+ compiler_use_next_block(c, end);
+ }
+ return 1;
+}
+
+static int
+compiler_call(struct compiler *c, expr_ty e)
+{
+ int n, code = 0;
+
+ VISIT(c, expr, e->v.Call.func);
+ n = asdl_seq_LEN(e->v.Call.args);
+ VISIT_SEQ(c, expr, e->v.Call.args);
+ if (e->v.Call.keywords) {
+ VISIT_SEQ(c, keyword, e->v.Call.keywords);
+ n |= asdl_seq_LEN(e->v.Call.keywords) << 8;
+ }
+ if (e->v.Call.starargs) {
+ VISIT(c, expr, e->v.Call.starargs);
+ code |= 1;
+ }
+ if (e->v.Call.kwargs) {
+ VISIT(c, expr, e->v.Call.kwargs);
+ code |= 2;
+ }
+ switch (code) {
+ case 0:
+ ADDOP_I(c, CALL_FUNCTION, n);
+ break;
+ case 1:
+ ADDOP_I(c, CALL_FUNCTION_VAR, n);
+ break;
+ case 2:
+ ADDOP_I(c, CALL_FUNCTION_KW, n);
+ break;
+ case 3:
+ ADDOP_I(c, CALL_FUNCTION_VAR_KW, n);
+ break;
+ }
+ return 1;
+}
+
+static int
+compiler_listcomp_generator(struct compiler *c, asdl_seq *generators,
+ int gen_index, expr_ty elt)
+{
+ /* generate code for the iterator, then each of the ifs,
+ and then write to the element */
+
+ comprehension_ty l;
+ basicblock *start, *anchor, *skip, *if_cleanup;
+ int i, n;
+
+ start = compiler_new_block(c);
+ skip = compiler_new_block(c);
+ if_cleanup = compiler_new_block(c);
+ anchor = compiler_new_block(c);
+
+ if (start == NULL || skip == NULL || if_cleanup == NULL ||
+ anchor == NULL)
+ return 0;
+
+ l = (comprehension_ty)asdl_seq_GET(generators, gen_index);
+ VISIT(c, expr, l->iter);
+ ADDOP(c, GET_ITER);
+ compiler_use_next_block(c, start);
+ ADDOP_JREL(c, FOR_ITER, anchor);
+ NEXT_BLOCK(c);
+ VISIT(c, expr, l->target);
+
+ /* XXX this needs to be cleaned up...a lot! */
+ n = asdl_seq_LEN(l->ifs);
+ for (i = 0; i < n; i++) {
+ expr_ty e = (expr_ty)asdl_seq_GET(l->ifs, i);
+ VISIT(c, expr, e);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
+ NEXT_BLOCK(c);
+ }
+
+ if (++gen_index < asdl_seq_LEN(generators))
+ if (!compiler_listcomp_generator(c, generators, gen_index, elt))
+ return 0;
+
+ /* only append after the last for generator */
+ if (gen_index >= asdl_seq_LEN(generators)) {
+ VISIT(c, expr, elt);
+ ADDOP_I(c, LIST_APPEND, gen_index+1);
+
+ compiler_use_next_block(c, skip);
+ }
+ compiler_use_next_block(c, if_cleanup);
+ ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+ compiler_use_next_block(c, anchor);
+
+ return 1;
+}
+
+static int
+compiler_listcomp(struct compiler *c, expr_ty e)
+{
+ assert(e->kind == ListComp_kind);
+ ADDOP_I(c, BUILD_LIST, 0);
+ return compiler_listcomp_generator(c, e->v.ListComp.generators, 0,
+ e->v.ListComp.elt);
+}
+
+/* Dict and set comprehensions and generator expressions work by creating a
+ nested function to perform the actual iteration. This means that the
+ iteration variables don't leak into the current scope.
+ The defined function is called immediately following its definition, with the
+ result of that call being the result of the expression.
+ The LC/SC version returns the populated container, while the GE version is
+ flagged in symtable.c as a generator, so it returns the generator object
+ when the function is called.
+ This code *knows* that the loop cannot contain break, continue, or return,
+ so it cheats and skips the SETUP_LOOP/POP_BLOCK steps used in normal loops.
+
+ Possible cleanups:
+ - iterate over the generator sequence instead of using recursion
+*/
+
+static int
+compiler_comprehension_generator(struct compiler *c,
+ asdl_seq *generators, int gen_index,
+ expr_ty elt, expr_ty val, int type)
+{
+ /* generate code for the iterator, then each of the ifs,
+ and then write to the element */
+
+ comprehension_ty gen;
+ basicblock *start, *anchor, *skip, *if_cleanup;
+ int i, n;
+
+ start = compiler_new_block(c);
+ skip = compiler_new_block(c);
+ if_cleanup = compiler_new_block(c);
+ anchor = compiler_new_block(c);
+
+ if (start == NULL || skip == NULL || if_cleanup == NULL ||
+ anchor == NULL)
+ return 0;
+
+ gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
+
+ if (gen_index == 0) {
+ /* Receive outermost iter as an implicit argument */
+ c->u->u_argcount = 1;
+ ADDOP_I(c, LOAD_FAST, 0);
+ }
+ else {
+ /* Sub-iter - calculate on the fly */
+ VISIT(c, expr, gen->iter);
+ ADDOP(c, GET_ITER);
+ }
+ compiler_use_next_block(c, start);
+ ADDOP_JREL(c, FOR_ITER, anchor);
+ NEXT_BLOCK(c);
+ VISIT(c, expr, gen->target);
+
+ /* XXX this needs to be cleaned up...a lot! */
+ n = asdl_seq_LEN(gen->ifs);
+ for (i = 0; i < n; i++) {
+ expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i);
+ VISIT(c, expr, e);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
+ NEXT_BLOCK(c);
+ }
+
+ if (++gen_index < asdl_seq_LEN(generators))
+ if (!compiler_comprehension_generator(c,
+ generators, gen_index,
+ elt, val, type))
+ return 0;
+
+ /* only append after the last for generator */
+ if (gen_index >= asdl_seq_LEN(generators)) {
+ /* comprehension specific code */
+ switch (type) {
+ case COMP_GENEXP:
+ VISIT(c, expr, elt);
+ ADDOP(c, YIELD_VALUE);
+ ADDOP(c, POP_TOP);
+ break;
+ case COMP_SETCOMP:
+ VISIT(c, expr, elt);
+ ADDOP_I(c, SET_ADD, gen_index + 1);
+ break;
+ case COMP_DICTCOMP:
+ /* With 'd[k] = v', v is evaluated before k, so we do
+ the same. */
+ VISIT(c, expr, val);
+ VISIT(c, expr, elt);
+ ADDOP_I(c, MAP_ADD, gen_index + 1);
+ break;
+ default:
+ return 0;
+ }
+
+ compiler_use_next_block(c, skip);
+ }
+ compiler_use_next_block(c, if_cleanup);
+ ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+ compiler_use_next_block(c, anchor);
+
+ return 1;
+}
+
+static int
+compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
+ asdl_seq *generators, expr_ty elt, expr_ty val)
+{
+ PyCodeObject *co = NULL;
+ expr_ty outermost_iter;
+
+ outermost_iter = ((comprehension_ty)
+ asdl_seq_GET(generators, 0))->iter;
+
+ if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
+ goto error;
+
+ if (type != COMP_GENEXP) {
+ int op;
+ switch (type) {
+ case COMP_SETCOMP:
+ op = BUILD_SET;
+ break;
+ case COMP_DICTCOMP:
+ op = BUILD_MAP;
+ break;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unknown comprehension type %d", type);
+ goto error_in_scope;
+ }
+
+ ADDOP_I(c, op, 0);
+ }
+
+ if (!compiler_comprehension_generator(c, generators, 0, elt,
+ val, type))
+ goto error_in_scope;
+
+ if (type != COMP_GENEXP) {
+ ADDOP(c, RETURN_VALUE);
+ }
+
+ co = assemble(c, 1);
+ compiler_exit_scope(c);
+ if (co == NULL)
+ goto error;
+
+ if (!compiler_make_closure(c, co, 0))
+ goto error;
+ Py_DECREF(co);
+
+ VISIT(c, expr, outermost_iter);
+ ADDOP(c, GET_ITER);
+ ADDOP_I(c, CALL_FUNCTION, 1);
+ return 1;
+error_in_scope:
+ compiler_exit_scope(c);
+error:
+ Py_XDECREF(co);
+ return 0;
+}
+
+static int
+compiler_genexp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<genexpr>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == GeneratorExp_kind);
+ return compiler_comprehension(c, e, COMP_GENEXP, name,
+ e->v.GeneratorExp.generators,
+ e->v.GeneratorExp.elt, NULL);
+}
+
+static int
+compiler_setcomp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<setcomp>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == SetComp_kind);
+ return compiler_comprehension(c, e, COMP_SETCOMP, name,
+ e->v.SetComp.generators,
+ e->v.SetComp.elt, NULL);
+}
+
+static int
+compiler_dictcomp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<dictcomp>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == DictComp_kind);
+ return compiler_comprehension(c, e, COMP_DICTCOMP, name,
+ e->v.DictComp.generators,
+ e->v.DictComp.key, e->v.DictComp.value);
+}
+
+static int
+compiler_visit_keyword(struct compiler *c, keyword_ty k)
+{
+ ADDOP_O(c, LOAD_CONST, k->arg, consts);
+ VISIT(c, expr, k->value);
+ return 1;
+}
+
+/* Test whether expression is constant. For constants, report
+ whether they are true or false.
+
+ Return values: 1 for true, 0 for false, -1 for non-constant.
+ */
+
+static int
+expr_constant(expr_ty e)
+{
+ switch (e->kind) {
+ case Num_kind:
+ return PyObject_IsTrue(e->v.Num.n);
+ case Str_kind:
+ return PyObject_IsTrue(e->v.Str.s);
+ case Name_kind:
+ /* __debug__ is not assignable, so we can optimize
+ * it away in if and while statements */
+ if (strcmp(PyString_AS_STRING(e->v.Name.id),
+ "__debug__") == 0)
+ return ! Py_OptimizeFlag;
+ /* fall through */
+ default:
+ return -1;
+ }
+}
+
+/*
+ Implements the with statement from PEP 343.
+
+ The semantics outlined in that PEP are as follows:
+
+ with EXPR as VAR:
+ BLOCK
+
+ It is implemented roughly as:
+
+ context = EXPR
+ exit = context.__exit__ # not calling it
+ value = context.__enter__()
+ try:
+ VAR = value # if VAR present in the syntax
+ BLOCK
+ finally:
+ if an exception was raised:
+ exc = copy of (exception, instance, traceback)
+ else:
+ exc = (None, None, None)
+ exit(*exc)
+ */
+static int
+compiler_with(struct compiler *c, stmt_ty s)
+{
+ basicblock *block, *finally;
+
+ assert(s->kind == With_kind);
+
+ block = compiler_new_block(c);
+ finally = compiler_new_block(c);
+ if (!block || !finally)
+ return 0;
+
+ /* Evaluate EXPR */
+ VISIT(c, expr, s->v.With.context_expr);
+ ADDOP_JREL(c, SETUP_WITH, finally);
+
+ /* SETUP_WITH pushes a finally block. */
+ compiler_use_next_block(c, block);
+ /* Note that the block is actually called SETUP_WITH in ceval.c, but
+ functions the same as SETUP_FINALLY except that exceptions are
+ normalized. */
+ if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
+ return 0;
+ }
+
+ if (s->v.With.optional_vars) {
+ VISIT(c, expr, s->v.With.optional_vars);
+ }
+ else {
+ /* Discard result from context.__enter__() */
+ ADDOP(c, POP_TOP);
+ }
+
+ /* BLOCK code */
+ VISIT_SEQ(c, stmt, s->v.With.body);
+
+ /* End of try block; start the finally block */
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, FINALLY_TRY, block);
+
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ compiler_use_next_block(c, finally);
+ if (!compiler_push_fblock(c, FINALLY_END, finally))
+ return 0;
+
+ /* Finally block starts; context.__exit__ is on the stack under
+ the exception or return information. Just issue our magic
+ opcode. */
+ ADDOP(c, WITH_CLEANUP);
+
+ /* Finally block ends. */
+ ADDOP(c, END_FINALLY);
+ compiler_pop_fblock(c, FINALLY_END, finally);
+ return 1;
+}
+
+static int
+compiler_visit_expr(struct compiler *c, expr_ty e)
+{
+ int i, n;
+
+ /* If expr e has a different line number than the last expr/stmt,
+ set a new line number for the next instruction.
+ */
+ if (e->lineno > c->u->u_lineno) {
+ c->u->u_lineno = e->lineno;
+ c->u->u_lineno_set = false;
+ }
+ switch (e->kind) {
+ case BoolOp_kind:
+ return compiler_boolop(c, e);
+ case BinOp_kind:
+ VISIT(c, expr, e->v.BinOp.left);
+ VISIT(c, expr, e->v.BinOp.right);
+ ADDOP(c, binop(c, e->v.BinOp.op));
+ break;
+ case UnaryOp_kind:
+ VISIT(c, expr, e->v.UnaryOp.operand);
+ ADDOP(c, unaryop(e->v.UnaryOp.op));
+ break;
+ case Lambda_kind:
+ return compiler_lambda(c, e);
+ case IfExp_kind:
+ return compiler_ifexp(c, e);
+ case Dict_kind:
+ n = asdl_seq_LEN(e->v.Dict.values);
+ ADDOP_I(c, BUILD_MAP, (n>0xFFFF ? 0xFFFF : n));
+ for (i = 0; i < n; i++) {
+ VISIT(c, expr,
+ (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
+ VISIT(c, expr,
+ (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
+ ADDOP(c, STORE_MAP);
+ }
+ break;
+ case Set_kind:
+ n = asdl_seq_LEN(e->v.Set.elts);
+ VISIT_SEQ(c, expr, e->v.Set.elts);
+ ADDOP_I(c, BUILD_SET, n);
+ break;
+ case ListComp_kind:
+ return compiler_listcomp(c, e);
+ case SetComp_kind:
+ return compiler_setcomp(c, e);
+ case DictComp_kind:
+ return compiler_dictcomp(c, e);
+ case GeneratorExp_kind:
+ return compiler_genexp(c, e);
+ case Yield_kind:
+ if (c->u->u_ste->ste_type != FunctionBlock)
+ return compiler_error(c, "'yield' outside function");
+ if (e->v.Yield.value) {
+ VISIT(c, expr, e->v.Yield.value);
+ }
+ else {
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ }
+ ADDOP(c, YIELD_VALUE);
+ break;
+ case Compare_kind:
+ return compiler_compare(c, e);
+ case Call_kind:
+ return compiler_call(c, e);
+ case Repr_kind:
+ VISIT(c, expr, e->v.Repr.value);
+ ADDOP(c, UNARY_CONVERT);
+ break;
+ case Num_kind:
+ ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts);
+ break;
+ case Str_kind:
+ ADDOP_O(c, LOAD_CONST, e->v.Str.s, consts);
+ break;
+ /* The following exprs can be assignment targets. */
+ case Attribute_kind:
+ if (e->v.Attribute.ctx != AugStore)
+ VISIT(c, expr, e->v.Attribute.value);
+ switch (e->v.Attribute.ctx) {
+ case AugLoad:
+ ADDOP(c, DUP_TOP);
+ /* Fall through to load */
+ case Load:
+ ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
+ break;
+ case AugStore:
+ ADDOP(c, ROT_TWO);
+ /* Fall through to save */
+ case Store:
+ ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
+ break;
+ case Del:
+ ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names);
+ break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid in attribute expression");
+ return 0;
+ }
+ break;
+ case Subscript_kind:
+ switch (e->v.Subscript.ctx) {
+ case AugLoad:
+ VISIT(c, expr, e->v.Subscript.value);
+ VISIT_SLICE(c, e->v.Subscript.slice, AugLoad);
+ break;
+ case Load:
+ VISIT(c, expr, e->v.Subscript.value);
+ VISIT_SLICE(c, e->v.Subscript.slice, Load);
+ break;
+ case AugStore:
+ VISIT_SLICE(c, e->v.Subscript.slice, AugStore);
+ break;
+ case Store:
+ VISIT(c, expr, e->v.Subscript.value);
+ VISIT_SLICE(c, e->v.Subscript.slice, Store);
+ break;
+ case Del:
+ VISIT(c, expr, e->v.Subscript.value);
+ VISIT_SLICE(c, e->v.Subscript.slice, Del);
+ break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid in subscript expression");
+ return 0;
+ }
+ break;
+ case Name_kind:
+ return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx);
+ /* child nodes of List and Tuple will have expr_context set */
+ case List_kind:
+ return compiler_list(c, e);
+ case Tuple_kind:
+ return compiler_tuple(c, e);
+ }
+ return 1;
+}
+
+static int
+compiler_augassign(struct compiler *c, stmt_ty s)
+{
+ expr_ty e = s->v.AugAssign.target;
+ expr_ty auge;
+
+ assert(s->kind == AugAssign_kind);
+
+ switch (e->kind) {
+ case Attribute_kind:
+ auge = Attribute(e->v.Attribute.value, e->v.Attribute.attr,
+ AugLoad, e->lineno, e->col_offset, c->c_arena);
+ if (auge == NULL)
+ return 0;
+ VISIT(c, expr, auge);
+ VISIT(c, expr, s->v.AugAssign.value);
+ ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+ auge->v.Attribute.ctx = AugStore;
+ VISIT(c, expr, auge);
+ break;
+ case Subscript_kind:
+ auge = Subscript(e->v.Subscript.value, e->v.Subscript.slice,
+ AugLoad, e->lineno, e->col_offset, c->c_arena);
+ if (auge == NULL)
+ return 0;
+ VISIT(c, expr, auge);
+ VISIT(c, expr, s->v.AugAssign.value);
+ ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+ auge->v.Subscript.ctx = AugStore;
+ VISIT(c, expr, auge);
+ break;
+ case Name_kind:
+ if (!compiler_nameop(c, e->v.Name.id, Load))
+ return 0;
+ VISIT(c, expr, s->v.AugAssign.value);
+ ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+ return compiler_nameop(c, e->v.Name.id, Store);
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "invalid node type (%d) for augmented assignment",
+ e->kind);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
+{
+ struct fblockinfo *f;
+ if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
+ PyErr_SetString(PyExc_SyntaxError,
+ "too many statically nested blocks");
+ return 0;
+ }
+ f = &c->u->u_fblock[c->u->u_nfblocks++];
+ f->fb_type = t;
+ f->fb_block = b;
+ return 1;
+}
+
+static void
+compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
+{
+ struct compiler_unit *u = c->u;
+ assert(u->u_nfblocks > 0);
+ u->u_nfblocks--;
+ assert(u->u_fblock[u->u_nfblocks].fb_type == t);
+ assert(u->u_fblock[u->u_nfblocks].fb_block == b);
+}
+
+static int
+compiler_in_loop(struct compiler *c) {
+ int i;
+ struct compiler_unit *u = c->u;
+ for (i = 0; i < u->u_nfblocks; ++i) {
+ if (u->u_fblock[i].fb_type == LOOP)
+ return 1;
+ }
+ return 0;
+}
+/* Raises a SyntaxError and returns 0.
+ If something goes wrong, a different exception may be raised.
+*/
+
+static int
+compiler_error(struct compiler *c, const char *errstr)
+{
+ PyObject *loc;
+ PyObject *u = NULL, *v = NULL;
+
+ loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno);
+ if (!loc) {
+ Py_INCREF(Py_None);
+ loc = Py_None;
+ }
+ u = Py_BuildValue("(ziOO)", c->c_filename, c->u->u_lineno,
+ Py_None, loc);
+ if (!u)
+ goto exit;
+ v = Py_BuildValue("(zO)", errstr, u);
+ if (!v)
+ goto exit;
+ PyErr_SetObject(PyExc_SyntaxError, v);
+ exit:
+ Py_DECREF(loc);
+ Py_XDECREF(u);
+ Py_XDECREF(v);
+ return 0;
+}
+
+static int
+compiler_handle_subscr(struct compiler *c, const char *kind,
+ expr_context_ty ctx)
+{
+ int op = 0;
+
+ /* XXX this code is duplicated */
+ switch (ctx) {
+ case AugLoad: /* fall through to Load */
+ case Load: op = BINARY_SUBSCR; break;
+ case AugStore:/* fall through to Store */
+ case Store: op = STORE_SUBSCR; break;
+ case Del: op = DELETE_SUBSCR; break;
+ case Param:
+ PyErr_Format(PyExc_SystemError,
+ "invalid %s kind %d in subscript\n",
+ kind, ctx);
+ return 0;
+ }
+ if (ctx == AugLoad) {
+ ADDOP_I(c, DUP_TOPX, 2);
+ }
+ else if (ctx == AugStore) {
+ ADDOP(c, ROT_THREE);
+ }
+ ADDOP(c, op);
+ return 1;
+}
+
+static int
+compiler_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
+{
+ int n = 2;
+ assert(s->kind == Slice_kind);
+
+ /* only handles the cases where BUILD_SLICE is emitted */
+ if (s->v.Slice.lower) {
+ VISIT(c, expr, s->v.Slice.lower);
+ }
+ else {
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ }
+
+ if (s->v.Slice.upper) {
+ VISIT(c, expr, s->v.Slice.upper);
+ }
+ else {
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ }
+
+ if (s->v.Slice.step) {
+ n++;
+ VISIT(c, expr, s->v.Slice.step);
+ }
+ ADDOP_I(c, BUILD_SLICE, n);
+ return 1;
+}
+
+static int
+compiler_simple_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
+{
+ int op = 0, slice_offset = 0, stack_count = 0;
+
+ assert(s->v.Slice.step == NULL);
+ if (s->v.Slice.lower) {
+ slice_offset++;
+ stack_count++;
+ if (ctx != AugStore)
+ VISIT(c, expr, s->v.Slice.lower);
+ }
+ if (s->v.Slice.upper) {
+ slice_offset += 2;
+ stack_count++;
+ if (ctx != AugStore)
+ VISIT(c, expr, s->v.Slice.upper);
+ }
+
+ if (ctx == AugLoad) {
+ switch (stack_count) {
+ case 0: ADDOP(c, DUP_TOP); break;
+ case 1: ADDOP_I(c, DUP_TOPX, 2); break;
+ case 2: ADDOP_I(c, DUP_TOPX, 3); break;
+ }
+ }
+ else if (ctx == AugStore) {
+ switch (stack_count) {
+ case 0: ADDOP(c, ROT_TWO); break;
+ case 1: ADDOP(c, ROT_THREE); break;
+ case 2: ADDOP(c, ROT_FOUR); break;
+ }
+ }
+
+ switch (ctx) {
+ case AugLoad: /* fall through to Load */
+ case Load: op = SLICE; break;
+ case AugStore:/* fall through to Store */
+ case Store: op = STORE_SLICE; break;
+ case Del: op = DELETE_SLICE; break;
+ case Param:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "param invalid in simple slice");
+ return 0;
+ }
+
+ ADDOP(c, op + slice_offset);
+ return 1;
+}
+
+static int
+compiler_visit_nested_slice(struct compiler *c, slice_ty s,
+ expr_context_ty ctx)
+{
+ switch (s->kind) {
+ case Ellipsis_kind:
+ ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
+ break;
+ case Slice_kind:
+ return compiler_slice(c, s, ctx);
+ case Index_kind:
+ VISIT(c, expr, s->v.Index.value);
+ break;
+ case ExtSlice_kind:
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "extended slice invalid in nested slice");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
+{
+ char * kindname = NULL;
+ switch (s->kind) {
+ case Index_kind:
+ kindname = "index";
+ if (ctx != AugStore) {
+ VISIT(c, expr, s->v.Index.value);
+ }
+ break;
+ case Ellipsis_kind:
+ kindname = "ellipsis";
+ if (ctx != AugStore) {
+ ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
+ }
+ break;
+ case Slice_kind:
+ kindname = "slice";
+ if (!s->v.Slice.step)
+ return compiler_simple_slice(c, s, ctx);
+ if (ctx != AugStore) {
+ if (!compiler_slice(c, s, ctx))
+ return 0;
+ }
+ break;
+ case ExtSlice_kind:
+ kindname = "extended slice";
+ if (ctx != AugStore) {
+ int i, n = asdl_seq_LEN(s->v.ExtSlice.dims);
+ for (i = 0; i < n; i++) {
+ slice_ty sub = (slice_ty)asdl_seq_GET(
+ s->v.ExtSlice.dims, i);
+ if (!compiler_visit_nested_slice(c, sub, ctx))
+ return 0;
+ }
+ ADDOP_I(c, BUILD_TUPLE, n);
+ }
+ break;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "invalid subscript kind %d", s->kind);
+ return 0;
+ }
+ return compiler_handle_subscr(c, kindname, ctx);
+}
+
+
+/* End of the compiler section, beginning of the assembler section */
+
+/* do depth-first search of basic block graph, starting with block.
+ post records the block indices in post-order.
+
+ XXX must handle implicit jumps from one block to next
+*/
+
+struct assembler {
+ PyObject *a_bytecode; /* string containing bytecode */
+ int a_offset; /* offset into bytecode */
+ int a_nblocks; /* number of reachable blocks */
+ basicblock **a_postorder; /* list of blocks in dfs postorder */
+ PyObject *a_lnotab; /* string containing lnotab */
+ int a_lnotab_off; /* offset into lnotab */
+ int a_lineno; /* last lineno of emitted instruction */
+ int a_lineno_off; /* bytecode offset of last lineno */
+};
+
+static void
+dfs(struct compiler *c, basicblock *b, struct assembler *a)
+{
+ int i;
+ struct instr *instr = NULL;
+
+ if (b->b_seen)
+ return;
+ b->b_seen = 1;
+ if (b->b_next != NULL)
+ dfs(c, b->b_next, a);
+ for (i = 0; i < b->b_iused; i++) {
+ instr = &b->b_instr[i];
+ if (instr->i_jrel || instr->i_jabs)
+ dfs(c, instr->i_target, a);
+ }
+ a->a_postorder[a->a_nblocks++] = b;
+}
+
+static int
+stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
+{
+ int i, target_depth;
+ struct instr *instr;
+ if (b->b_seen || b->b_startdepth >= depth)
+ return maxdepth;
+ b->b_seen = 1;
+ b->b_startdepth = depth;
+ for (i = 0; i < b->b_iused; i++) {
+ instr = &b->b_instr[i];
+ depth += opcode_stack_effect(instr->i_opcode, instr->i_oparg);
+ if (depth > maxdepth)
+ maxdepth = depth;
+ assert(depth >= 0); /* invalid code or bug in stackdepth() */
+ if (instr->i_jrel || instr->i_jabs) {
+ target_depth = depth;
+ if (instr->i_opcode == FOR_ITER) {
+ target_depth = depth-2;
+ }
+ else if (instr->i_opcode == SETUP_FINALLY ||
+ instr->i_opcode == SETUP_EXCEPT) {
+ target_depth = depth+3;
+ if (target_depth > maxdepth)
+ maxdepth = target_depth;
+ }
+ else if (instr->i_opcode == JUMP_IF_TRUE_OR_POP ||
+ instr->i_opcode == JUMP_IF_FALSE_OR_POP)
+ depth = depth - 1;
+ maxdepth = stackdepth_walk(c, instr->i_target,
+ target_depth, maxdepth);
+ if (instr->i_opcode == JUMP_ABSOLUTE ||
+ instr->i_opcode == JUMP_FORWARD) {
+ goto out; /* remaining code is dead */
+ }
+ }
+ }
+ if (b->b_next)
+ maxdepth = stackdepth_walk(c, b->b_next, depth, maxdepth);
+out:
+ b->b_seen = 0;
+ return maxdepth;
+}
+
+/* Find the flow path that needs the largest stack. We assume that
+ * cycles in the flow graph have no net effect on the stack depth.
+ */
+static int
+stackdepth(struct compiler *c)
+{
+ basicblock *b, *entryblock;
+ entryblock = NULL;
+ for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+ b->b_seen = 0;
+ b->b_startdepth = INT_MIN;
+ entryblock = b;
+ }
+ if (!entryblock)
+ return 0;
+ return stackdepth_walk(c, entryblock, 0, 0);
+}
+
+static int
+assemble_init(struct assembler *a, int nblocks, int firstlineno)
+{
+ memset(a, 0, sizeof(struct assembler));
+ a->a_lineno = firstlineno;
+ a->a_bytecode = PyString_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
+ if (!a->a_bytecode)
+ return 0;
+ a->a_lnotab = PyString_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
+ if (!a->a_lnotab)
+ return 0;
+ if (nblocks > PY_SIZE_MAX / sizeof(basicblock *)) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ a->a_postorder = (basicblock **)PyObject_Malloc(
+ sizeof(basicblock *) * nblocks);
+ if (!a->a_postorder) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ return 1;
+}
+
+static void
+assemble_free(struct assembler *a)
+{
+ Py_XDECREF(a->a_bytecode);
+ Py_XDECREF(a->a_lnotab);
+ if (a->a_postorder)
+ PyObject_Free(a->a_postorder);
+}
+
+/* Return the size of a basic block in bytes. */
+
+static int
+instrsize(struct instr *instr)
+{
+ if (!instr->i_hasarg)
+ return 1; /* 1 byte for the opcode*/
+ if (instr->i_oparg > 0xffff)
+ return 6; /* 1 (opcode) + 1 (EXTENDED_ARG opcode) + 2 (oparg) + 2(oparg extended) */
+ return 3; /* 1 (opcode) + 2 (oparg) */
+}
+
+static int
+blocksize(basicblock *b)
+{
+ int i;
+ int size = 0;
+
+ for (i = 0; i < b->b_iused; i++)
+ size += instrsize(&b->b_instr[i]);
+ return size;
+}
+
+/* Appends a pair to the end of the line number table, a_lnotab, representing
+ the instruction's bytecode offset and line number. See
+ Objects/lnotab_notes.txt for the description of the line number table. */
+
+static int
+assemble_lnotab(struct assembler *a, struct instr *i)
+{
+ int d_bytecode, d_lineno;
+ int len;
+ unsigned char *lnotab;
+
+ d_bytecode = a->a_offset - a->a_lineno_off;
+ d_lineno = i->i_lineno - a->a_lineno;
+
+ assert(d_bytecode >= 0);
+
+ if(d_bytecode == 0 && d_lineno == 0)
+ return 1;
+
+ if (d_bytecode > 255) {
+ int j, nbytes, ncodes = d_bytecode / 255;
+ nbytes = a->a_lnotab_off + 2 * ncodes;
+ len = PyString_GET_SIZE(a->a_lnotab);
+ if (nbytes >= len) {
+ if ((len <= INT_MAX / 2) && (len * 2 < nbytes))
+ len = nbytes;
+ else if (len <= INT_MAX / 2)
+ len *= 2;
+ else {
+ PyErr_NoMemory();
+ return 0;
+ }
+ if (_PyString_Resize(&a->a_lnotab, len) < 0)
+ return 0;
+ }
+ lnotab = (unsigned char *)
+ PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+ for (j = 0; j < ncodes; j++) {
+ *lnotab++ = 255;
+ *lnotab++ = 0;
+ }
+ d_bytecode -= ncodes * 255;
+ a->a_lnotab_off += ncodes * 2;
+ }
+ assert(0 <= d_bytecode && d_bytecode <= 255);
+
+ if (d_lineno < -128 || 127 < d_lineno) {
+ int j, nbytes, ncodes, k;
+ if (d_lineno < 0) {
+ k = -128;
+ /* use division on positive numbers */
+ ncodes = (-d_lineno) / 128;
+ }
+ else {
+ k = 127;
+ ncodes = d_lineno / 127;
+ }
+ d_lineno -= ncodes * k;
+ assert(ncodes >= 1);
+ nbytes = a->a_lnotab_off + 2 * ncodes;
+ len = PyString_GET_SIZE(a->a_lnotab);
+ if (nbytes >= len) {
+ if ((len <= INT_MAX / 2) && len * 2 < nbytes)
+ len = nbytes;
+ else if (len <= INT_MAX / 2)
+ len *= 2;
+ else {
+ PyErr_NoMemory();
+ return 0;
+ }
+ if (_PyString_Resize(&a->a_lnotab, len) < 0)
+ return 0;
+ }
+ lnotab = (unsigned char *)
+ PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+ *lnotab++ = d_bytecode;
+ *lnotab++ = k;
+ d_bytecode = 0;
+ for (j = 1; j < ncodes; j++) {
+ *lnotab++ = 0;
+ *lnotab++ = k;
+ }
+ a->a_lnotab_off += ncodes * 2;
+ }
+ assert(-128 <= d_lineno && d_lineno <= 127);
+
+ len = PyString_GET_SIZE(a->a_lnotab);
+ if (a->a_lnotab_off + 2 >= len) {
+ if (_PyString_Resize(&a->a_lnotab, len * 2) < 0)
+ return 0;
+ }
+ lnotab = (unsigned char *)
+ PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+
+ a->a_lnotab_off += 2;
+ if (d_bytecode) {
+ *lnotab++ = d_bytecode;
+ *lnotab++ = d_lineno;
+ }
+ else { /* First line of a block; def stmt, etc. */
+ *lnotab++ = 0;
+ *lnotab++ = d_lineno;
+ }
+ a->a_lineno = i->i_lineno;
+ a->a_lineno_off = a->a_offset;
+ return 1;
+}
+
+/* assemble_emit()
+ Extend the bytecode with a new instruction.
+ Update lnotab if necessary.
+*/
+
+static int
+assemble_emit(struct assembler *a, struct instr *i)
+{
+ int size, arg = 0, ext = 0;
+ Py_ssize_t len = PyString_GET_SIZE(a->a_bytecode);
+ char *code;
+
+ size = instrsize(i);
+ if (i->i_hasarg) {
+ arg = i->i_oparg;
+ ext = arg >> 16;
+ }
+ if (i->i_lineno && !assemble_lnotab(a, i))
+ return 0;
+ if (a->a_offset + size >= len) {
+ if (len > PY_SSIZE_T_MAX / 2)
+ return 0;
+ if (_PyString_Resize(&a->a_bytecode, len * 2) < 0)
+ return 0;
+ }
+ code = PyString_AS_STRING(a->a_bytecode) + a->a_offset;
+ a->a_offset += size;
+ if (size == 6) {
+ assert(i->i_hasarg);
+ *code++ = (char)EXTENDED_ARG;
+ *code++ = ext & 0xff;
+ *code++ = ext >> 8;
+ arg &= 0xffff;
+ }
+ *code++ = i->i_opcode;
+ if (i->i_hasarg) {
+ assert(size == 3 || size == 6);
+ *code++ = arg & 0xff;
+ *code++ = arg >> 8;
+ }
+ return 1;
+}
+
+static void
+assemble_jump_offsets(struct assembler *a, struct compiler *c)
+{
+ basicblock *b;
+ int bsize, totsize, extended_arg_count = 0, last_extended_arg_count;
+ int i;
+
+ /* Compute the size of each block and fixup jump args.
+ Replace block pointer with position in bytecode. */
+ do {
+ totsize = 0;
+ for (i = a->a_nblocks - 1; i >= 0; i--) {
+ b = a->a_postorder[i];
+ bsize = blocksize(b);
+ b->b_offset = totsize;
+ totsize += bsize;
+ }
+ last_extended_arg_count = extended_arg_count;
+ extended_arg_count = 0;
+ for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+ bsize = b->b_offset;
+ for (i = 0; i < b->b_iused; i++) {
+ struct instr *instr = &b->b_instr[i];
+ /* Relative jumps are computed relative to
+ the instruction pointer after fetching
+ the jump instruction.
+ */
+ bsize += instrsize(instr);
+ if (instr->i_jabs)
+ instr->i_oparg = instr->i_target->b_offset;
+ else if (instr->i_jrel) {
+ int delta = instr->i_target->b_offset - bsize;
+ instr->i_oparg = delta;
+ }
+ else
+ continue;
+ if (instr->i_oparg > 0xffff)
+ extended_arg_count++;
+ }
+ }
+
+ /* XXX: This is an awful hack that could hurt performance, but
+ on the bright side it should work until we come up
+ with a better solution.
+
+ The issue is that in the first loop blocksize() is called
+ which calls instrsize() which requires i_oparg be set
+ appropriately. There is a bootstrap problem because
+ i_oparg is calculated in the second loop above.
+
+ So we loop until we stop seeing new EXTENDED_ARGs.
+ The only EXTENDED_ARGs that could be popping up are
+ ones in jump instructions. So this should converge
+ fairly quickly.
+ */
+ } while (last_extended_arg_count != extended_arg_count);
+}
+
+static PyObject *
+dict_keys_inorder(PyObject *dict, int offset)
+{
+ PyObject *tuple, *k, *v;
+ Py_ssize_t i, pos = 0, size = PyDict_Size(dict);
+
+ tuple = PyTuple_New(size);
+ if (tuple == NULL)
+ return NULL;
+ while (PyDict_Next(dict, &pos, &k, &v)) {
+ i = PyInt_AS_LONG(v);
+ /* The keys of the dictionary are tuples. (see compiler_add_o)
+ The object we want is always first, though. */
+ k = PyTuple_GET_ITEM(k, 1);
+ Py_INCREF(k);
+ assert((i - offset) < size);
+ assert((i - offset) >= 0);
+ PyTuple_SET_ITEM(tuple, i - offset, k);
+ }
+ return tuple;
+}
+
+static int
+compute_code_flags(struct compiler *c)
+{
+ PySTEntryObject *ste = c->u->u_ste;
+ int flags = 0, n;
+ if (ste->ste_type != ModuleBlock)
+ flags |= CO_NEWLOCALS;
+ if (ste->ste_type == FunctionBlock) {
+ if (!ste->ste_unoptimized)
+ flags |= CO_OPTIMIZED;
+ if (ste->ste_nested)
+ flags |= CO_NESTED;
+ if (ste->ste_generator)
+ flags |= CO_GENERATOR;
+ if (ste->ste_varargs)
+ flags |= CO_VARARGS;
+ if (ste->ste_varkeywords)
+ flags |= CO_VARKEYWORDS;
+ }
+
+ /* (Only) inherit compilerflags in PyCF_MASK */
+ flags |= (c->c_flags->cf_flags & PyCF_MASK);
+
+ n = PyDict_Size(c->u->u_freevars);
+ if (n < 0)
+ return -1;
+ if (n == 0) {
+ n = PyDict_Size(c->u->u_cellvars);
+ if (n < 0)
+ return -1;
+ if (n == 0) {
+ flags |= CO_NOFREE;
+ }
+ }
+
+ return flags;
+}
+
+static PyCodeObject *
+makecode(struct compiler *c, struct assembler *a)
+{
+ PyObject *tmp;
+ PyCodeObject *co = NULL;
+ PyObject *consts = NULL;
+ PyObject *names = NULL;
+ PyObject *varnames = NULL;
+ PyObject *filename = NULL;
+ PyObject *name = NULL;
+ PyObject *freevars = NULL;
+ PyObject *cellvars = NULL;
+ PyObject *bytecode = NULL;
+ int nlocals, flags;
+
+ tmp = dict_keys_inorder(c->u->u_consts, 0);
+ if (!tmp)
+ goto error;
+ consts = PySequence_List(tmp); /* optimize_code requires a list */
+ Py_DECREF(tmp);
+
+ names = dict_keys_inorder(c->u->u_names, 0);
+ varnames = dict_keys_inorder(c->u->u_varnames, 0);
+ if (!consts || !names || !varnames)
+ goto error;
+
+ cellvars = dict_keys_inorder(c->u->u_cellvars, 0);
+ if (!cellvars)
+ goto error;
+ freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_Size(cellvars));
+ if (!freevars)
+ goto error;
+ filename = PyString_FromString(c->c_filename);
+ if (!filename)
+ goto error;
+
+ nlocals = PyDict_Size(c->u->u_varnames);
+ flags = compute_code_flags(c);
+ if (flags < 0)
+ goto error;
+
+ bytecode = PyCode_Optimize(a->a_bytecode, consts, names, a->a_lnotab);
+ if (!bytecode)
+ goto error;
+
+ tmp = PyList_AsTuple(consts); /* PyCode_New requires a tuple */
+ if (!tmp)
+ goto error;
+ Py_DECREF(consts);
+ consts = tmp;
+
+ co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c), flags,
+ bytecode, consts, names, varnames,
+ freevars, cellvars,
+ filename, c->u->u_name,
+ c->u->u_firstlineno,
+ a->a_lnotab);
+ error:
+ Py_XDECREF(consts);
+ Py_XDECREF(names);
+ Py_XDECREF(varnames);
+ Py_XDECREF(filename);
+ Py_XDECREF(name);
+ Py_XDECREF(freevars);
+ Py_XDECREF(cellvars);
+ Py_XDECREF(bytecode);
+ return co;
+}
+
+
+/* For debugging purposes only */
+#if 0
+static void
+dump_instr(const struct instr *i)
+{
+ const char *jrel = i->i_jrel ? "jrel " : "";
+ const char *jabs = i->i_jabs ? "jabs " : "";
+ char arg[128];
+
+ *arg = '\0';
+ if (i->i_hasarg)
+ sprintf(arg, "arg: %d ", i->i_oparg);
+
+ fprintf(stderr, "line: %d, opcode: %d %s%s%s\n",
+ i->i_lineno, i->i_opcode, arg, jabs, jrel);
+}
+
+static void
+dump_basicblock(const basicblock *b)
+{
+ const char *seen = b->b_seen ? "seen " : "";
+ const char *b_return = b->b_return ? "return " : "";
+ fprintf(stderr, "used: %d, depth: %d, offset: %d %s%s\n",
+ b->b_iused, b->b_startdepth, b->b_offset, seen, b_return);
+ if (b->b_instr) {
+ int i;
+ for (i = 0; i < b->b_iused; i++) {
+ fprintf(stderr, " [%02d] ", i);
+ dump_instr(b->b_instr + i);
+ }
+ }
+}
+#endif
+
+static PyCodeObject *
+assemble(struct compiler *c, int addNone)
+{
+ basicblock *b, *entryblock;
+ struct assembler a;
+ int i, j, nblocks;
+ PyCodeObject *co = NULL;
+
+ /* Make sure every block that falls off the end returns None.
+ XXX NEXT_BLOCK() isn't quite right, because if the last
+ block ends with a jump or return b_next shouldn't set.
+ */
+ if (!c->u->u_curblock->b_return) {
+ NEXT_BLOCK(c);
+ if (addNone)
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, RETURN_VALUE);
+ }
+
+ nblocks = 0;
+ entryblock = NULL;
+ for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+ nblocks++;
+ entryblock = b;
+ }
+
+ /* Set firstlineno if it wasn't explicitly set. */
+ if (!c->u->u_firstlineno) {
+ if (entryblock && entryblock->b_instr)
+ c->u->u_firstlineno = entryblock->b_instr->i_lineno;
+ else
+ c->u->u_firstlineno = 1;
+ }
+ if (!assemble_init(&a, nblocks, c->u->u_firstlineno))
+ goto error;
+ dfs(c, entryblock, &a);
+
+ /* Can't modify the bytecode after computing jump offsets. */
+ assemble_jump_offsets(&a, c);
+
+ /* Emit code in reverse postorder from dfs. */
+ for (i = a.a_nblocks - 1; i >= 0; i--) {
+ b = a.a_postorder[i];
+ for (j = 0; j < b->b_iused; j++)
+ if (!assemble_emit(&a, &b->b_instr[j]))
+ goto error;
+ }
+
+ if (_PyString_Resize(&a.a_lnotab, a.a_lnotab_off) < 0)
+ goto error;
+ if (_PyString_Resize(&a.a_bytecode, a.a_offset) < 0)
+ goto error;
+
+ co = makecode(c, &a);
+ error:
+ assemble_free(&a);
+ return co;
+}
diff --git a/contrib/tools/python/src/Python/dtoa.c b/contrib/tools/python/src/Python/dtoa.c
new file mode 100644
index 0000000000..73e23af010
--- /dev/null
+++ b/contrib/tools/python/src/Python/dtoa.c
@@ -0,0 +1,2949 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/****************************************************************
+ * This is dtoa.c by David M. Gay, downloaded from
+ * http://www.netlib.org/fp/dtoa.c on April 15, 2009 and modified for
+ * inclusion into the Python core by Mark E. T. Dickinson and Eric V. Smith.
+ *
+ * Please remember to check http://www.netlib.org/fp regularly (and especially
+ * before any Python release) for bugfixes and updates.
+ *
+ * The major modifications from Gay's original code are as follows:
+ *
+ * 0. The original code has been specialized to Python's needs by removing
+ * many of the #ifdef'd sections. In particular, code to support VAX and
+ * IBM floating-point formats, hex NaNs, hex floats, locale-aware
+ * treatment of the decimal point, and setting of the inexact flag have
+ * been removed.
+ *
+ * 1. We use PyMem_Malloc and PyMem_Free in place of malloc and free.
+ *
+ * 2. The public functions strtod, dtoa and freedtoa all now have
+ * a _Py_dg_ prefix.
+ *
+ * 3. Instead of assuming that PyMem_Malloc always succeeds, we thread
+ * PyMem_Malloc failures through the code. The functions
+ *
+ * Balloc, multadd, s2b, i2b, mult, pow5mult, lshift, diff, d2b
+ *
+ * of return type *Bigint all return NULL to indicate a malloc failure.
+ * Similarly, rv_alloc and nrv_alloc (return type char *) return NULL on
+ * failure. bigcomp now has return type int (it used to be void) and
+ * returns -1 on failure and 0 otherwise. _Py_dg_dtoa returns NULL
+ * on failure. _Py_dg_strtod indicates failure due to malloc failure
+ * by returning -1.0, setting errno=ENOMEM and *se to s00.
+ *
+ * 4. The static variable dtoa_result has been removed. Callers of
+ * _Py_dg_dtoa are expected to call _Py_dg_freedtoa to free
+ * the memory allocated by _Py_dg_dtoa.
+ *
+ * 5. The code has been reformatted to better fit with Python's
+ * C style guide (PEP 7).
+ *
+ * 6. A bug in the memory allocation has been fixed: to avoid FREEing memory
+ * that hasn't been MALLOC'ed, private_mem should only be used when k <=
+ * Kmax.
+ *
+ * 7. _Py_dg_strtod has been modified so that it doesn't accept strings with
+ * leading whitespace.
+ *
+ ***************************************************************/
+
+/* Please send bug reports for the original dtoa.c code to David M. Gay (dmg
+ * at acm dot org, with " at " changed at "@" and " dot " changed to ".").
+ * Please report bugs for this modified version using the Python issue tracker
+ * (http://bugs.python.org). */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/* Linking of Python's #defines to Gay's #defines starts here. */
+
+#include "Python.h"
+
+/* if PY_NO_SHORT_FLOAT_REPR is defined, then don't even try to compile
+ the following code */
+#ifndef PY_NO_SHORT_FLOAT_REPR
+
+#include "float.h"
+
+#define MALLOC PyMem_Malloc
+#define FREE PyMem_Free
+
+/* This code should also work for ARM mixed-endian format on little-endian
+ machines, where doubles have byte order 45670123 (in increasing address
+ order, 0 being the least significant byte). */
+#ifdef DOUBLE_IS_LITTLE_ENDIAN_IEEE754
+# define IEEE_8087
+#endif
+#if defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) || \
+ defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
+# define IEEE_MC68k
+#endif
+#if defined(IEEE_8087) + defined(IEEE_MC68k) != 1
+#error "Exactly one of IEEE_8087 or IEEE_MC68k should be defined."
+#endif
+
+/* The code below assumes that the endianness of integers matches the
+ endianness of the two 32-bit words of a double. Check this. */
+#if defined(WORDS_BIGENDIAN) && (defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) || \
+ defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754))
+#error "doubles and ints have incompatible endianness"
+#endif
+
+#if !defined(WORDS_BIGENDIAN) && defined(DOUBLE_IS_BIG_ENDIAN_IEEE754)
+#error "doubles and ints have incompatible endianness"
+#endif
+
+
+#if defined(HAVE_UINT32_T) && defined(HAVE_INT32_T)
+typedef PY_UINT32_T ULong;
+typedef PY_INT32_T Long;
+#else
+#error "Failed to find an exact-width 32-bit integer type"
+#endif
+
+#if defined(HAVE_UINT64_T)
+#define ULLong PY_UINT64_T
+#else
+#undef ULLong
+#endif
+
+#undef DEBUG
+#ifdef Py_DEBUG
+#define DEBUG
+#endif
+
+/* End Python #define linking */
+
+#ifdef DEBUG
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+#ifndef STRTOD_DIGLIM
+#define STRTOD_DIGLIM 40
+#endif
+
+/* maximum permitted exponent value for strtod; exponents larger than
+ MAX_ABS_EXP in absolute value get truncated to +-MAX_ABS_EXP. MAX_ABS_EXP
+ should fit into an int. */
+#ifndef MAX_ABS_EXP
+#define MAX_ABS_EXP 1100000000U
+#endif
+/* Bound on length of pieces of input strings in _Py_dg_strtod; specifically,
+ this is used to bound the total number of digits ignoring leading zeros and
+ the number of digits that follow the decimal point. Ideally, MAX_DIGITS
+ should satisfy MAX_DIGITS + 400 < MAX_ABS_EXP; that ensures that the
+ exponent clipping in _Py_dg_strtod can't affect the value of the output. */
+#ifndef MAX_DIGITS
+#define MAX_DIGITS 1000000000U
+#endif
+
+/* Guard against trying to use the above values on unusual platforms with ints
+ * of width less than 32 bits. */
+#if MAX_ABS_EXP > INT_MAX
+#error "MAX_ABS_EXP should fit in an int"
+#endif
+#if MAX_DIGITS > INT_MAX
+#error "MAX_DIGITS should fit in an int"
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+ ((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+ ((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Nbits 53
+#define Bias 1023
+#define Emax 1023
+#define Emin (-1022)
+#define Etiny (-1074) /* smallest denormal is 2**Etiny */
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#define Rounding Flt_Rounds
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+/* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */
+
+typedef struct BCinfo BCinfo;
+struct
+BCinfo {
+ int e0, nd, nd0, scale;
+};
+
+#define FFFFFFFF 0xffffffffUL
+
+#define Kmax 7
+
+/* struct Bigint is used to represent arbitrary-precision integers. These
+ integers are stored in sign-magnitude format, with the magnitude stored as
+ an array of base 2**32 digits. Bigints are always normalized: if x is a
+ Bigint then x->wds >= 1, and either x->wds == 1 or x[wds-1] is nonzero.
+
+ The Bigint fields are as follows:
+
+ - next is a header used by Balloc and Bfree to keep track of lists
+ of freed Bigints; it's also used for the linked list of
+ powers of 5 of the form 5**2**i used by pow5mult.
+ - k indicates which pool this Bigint was allocated from
+ - maxwds is the maximum number of words space was allocated for
+ (usually maxwds == 2**k)
+ - sign is 1 for negative Bigints, 0 for positive. The sign is unused
+ (ignored on inputs, set to 0 on outputs) in almost all operations
+ involving Bigints: a notable exception is the diff function, which
+ ignores signs on inputs but sets the sign of the output correctly.
+ - wds is the actual number of significant words
+ - x contains the vector of words (digits) for this Bigint, from least
+ significant (x[0]) to most significant (x[wds-1]).
+*/
+
+struct
+Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+};
+
+typedef struct Bigint Bigint;
+
+#ifndef Py_USING_MEMORY_DEBUGGER
+
+/* Memory management: memory is allocated from, and returned to, Kmax+1 pools
+ of memory, where pool k (0 <= k <= Kmax) is for Bigints b with b->maxwds ==
+ 1 << k. These pools are maintained as linked lists, with freelist[k]
+ pointing to the head of the list for pool k.
+
+ On allocation, if there's no free slot in the appropriate pool, MALLOC is
+ called to get more memory. This memory is not returned to the system until
+ Python quits. There's also a private memory pool that's allocated from
+ in preference to using MALLOC.
+
+ For Bigints with more than (1 << Kmax) digits (which implies at least 1233
+ decimal digits), memory is directly allocated using MALLOC, and freed using
+ FREE.
+
+ XXX: it would be easy to bypass this memory-management system and
+ translate each call to Balloc into a call to PyMem_Malloc, and each
+ Bfree to PyMem_Free. Investigate whether this has any significant
+ performance on impact. */
+
+static Bigint *freelist[Kmax+1];
+
+/* Allocate space for a Bigint with up to 1<<k digits */
+
+static Bigint *
+Balloc(int k)
+{
+ int x;
+ Bigint *rv;
+ unsigned int len;
+
+ if (k <= Kmax && (rv = freelist[k]))
+ freelist[k] = rv->next;
+ else {
+ x = 1 << k;
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+ if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+ rv = (Bigint*)pmem_next;
+ pmem_next += len;
+ }
+ else {
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+ if (rv == NULL)
+ return NULL;
+ }
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+/* Free a Bigint allocated with Balloc */
+
+static void
+Bfree(Bigint *v)
+{
+ if (v) {
+ if (v->k > Kmax)
+ FREE((void*)v);
+ else {
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ }
+ }
+}
+
+#else
+
+/* Alternative versions of Balloc and Bfree that use PyMem_Malloc and
+ PyMem_Free directly in place of the custom memory allocation scheme above.
+ These are provided for the benefit of memory debugging tools like
+ Valgrind. */
+
+/* Allocate space for a Bigint with up to 1<<k digits */
+
+static Bigint *
+Balloc(int k)
+{
+ int x;
+ Bigint *rv;
+ unsigned int len;
+
+ x = 1 << k;
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+ if (rv == NULL)
+ return NULL;
+
+ rv->k = k;
+ rv->maxwds = x;
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+/* Free a Bigint allocated with Balloc */
+
+static void
+Bfree(Bigint *v)
+{
+ if (v) {
+ FREE((void*)v);
+ }
+}
+
+#endif /* Py_USING_MEMORY_DEBUGGER */
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+ y->wds*sizeof(Long) + 2*sizeof(int))
+
+/* Multiply a Bigint b by m and add a. Either modifies b in place and returns
+ a pointer to the modified b, or Bfrees b and returns a pointer to a copy.
+ On failure, return NULL. In this case, b will have been already freed. */
+
+static Bigint *
+multadd(Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+#ifdef ULLong
+ ULong *x;
+ ULLong carry, y;
+#else
+ ULong carry, *x, y;
+ ULong xi, z;
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = (ULong)(y & FFFFFFFF);
+#else
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#endif
+ }
+ while(++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ if (b1 == NULL){
+ Bfree(b);
+ return NULL;
+ }
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (ULong)carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+/* convert a string s containing nd decimal digits (possibly containing a
+ decimal separator at position nd0, which is ignored) to a Bigint. This
+ function carries on where the parsing code in _Py_dg_strtod leaves off: on
+ entry, y9 contains the result of converting the first 9 digits. Returns
+ NULL on failure. */
+
+static Bigint *
+s2b(const char *s, int nd0, int nd, ULong y9)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+ b = Balloc(k);
+ if (b == NULL)
+ return NULL;
+ b->x[0] = y9;
+ b->wds = 1;
+
+ if (nd <= 9)
+ return b;
+
+ s += 9;
+ for (i = 9; i < nd0; i++) {
+ b = multadd(b, 10, *s++ - '0');
+ if (b == NULL)
+ return NULL;
+ }
+ s++;
+ for(; i < nd; i++) {
+ b = multadd(b, 10, *s++ - '0');
+ if (b == NULL)
+ return NULL;
+ }
+ return b;
+}
+
+/* count leading 0 bits in the 32-bit integer x. */
+
+static int
+hi0bits(ULong x)
+{
+ int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+/* count trailing 0 bits in the 32-bit integer y, and shift y right by that
+ number of bits. */
+
+static int
+lo0bits(ULong *y)
+{
+ int k;
+ ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+/* convert a small nonnegative integer to a Bigint */
+
+static Bigint *
+i2b(int i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ if (b == NULL)
+ return NULL;
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+/* multiply two Bigints. Returns a new Bigint, or NULL on failure. Ignores
+ the signs of a and b. */
+
+static Bigint *
+mult(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+ ULong z2;
+#endif
+
+ if ((!a->x[0] && a->wds == 1) || (!b->x[0] && b->wds == 1)) {
+ c = Balloc(0);
+ if (c == NULL)
+ return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ if (c == NULL)
+ return NULL;
+ for(x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for(; xb < xbe; xc0++) {
+ if ((y = *xb++)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (ULong)(z & FFFFFFFF);
+ }
+ while(x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#else
+ for(; xb < xbe; xb++, xc0++) {
+ if (y = *xb & 0xffff) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ if (y = *xb >> 16) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ }
+ while(x < xae);
+ *xc = z2;
+ }
+ }
+#endif
+ for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+}
+
+#ifndef Py_USING_MEMORY_DEBUGGER
+
+/* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */
+
+static Bigint *p5s;
+
+/* multiply the Bigint b by 5**k. Returns a pointer to the result, or NULL on
+ failure; if the returned pointer is distinct from b then the original
+ Bigint b will have been Bfree'd. Ignores the sign of b. */
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3)) {
+ b = multadd(b, p05[i-1], 0);
+ if (b == NULL)
+ return NULL;
+ }
+
+ if (!(k >>= 2))
+ return b;
+ p5 = p5s;
+ if (!p5) {
+ /* first time */
+ p5 = i2b(625);
+ if (p5 == NULL) {
+ Bfree(b);
+ return NULL;
+ }
+ p5s = p5;
+ p5->next = 0;
+ }
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ if (b == NULL)
+ return NULL;
+ }
+ if (!(k >>= 1))
+ break;
+ p51 = p5->next;
+ if (!p51) {
+ p51 = mult(p5,p5);
+ if (p51 == NULL) {
+ Bfree(b);
+ return NULL;
+ }
+ p51->next = 0;
+ p5->next = p51;
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+#else
+
+/* Version of pow5mult that doesn't cache powers of 5. Provided for
+ the benefit of memory debugging tools like Valgrind. */
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3)) {
+ b = multadd(b, p05[i-1], 0);
+ if (b == NULL)
+ return NULL;
+ }
+
+ if (!(k >>= 2))
+ return b;
+ p5 = i2b(625);
+ if (p5 == NULL) {
+ Bfree(b);
+ return NULL;
+ }
+
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ if (b == NULL) {
+ Bfree(p5);
+ return NULL;
+ }
+ }
+ if (!(k >>= 1))
+ break;
+ p51 = mult(p5, p5);
+ Bfree(p5);
+ p5 = p51;
+ if (p5 == NULL) {
+ Bfree(b);
+ return NULL;
+ }
+ }
+ Bfree(p5);
+ return b;
+}
+
+#endif /* Py_USING_MEMORY_DEBUGGER */
+
+/* shift a Bigint b left by k bits. Return a pointer to the shifted result,
+ or NULL on failure. If the returned pointer is distinct from b then the
+ original b will have been Bfree'd. Ignores the sign of b. */
+
+static Bigint *
+lshift(Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+ if (!k || (!b->x[0] && b->wds == 1))
+ return b;
+
+ n = k >> 5;
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for(i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ if (b1 == NULL) {
+ Bfree(b);
+ return NULL;
+ }
+ x1 = b1->x;
+ for(i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if ((*x1 = z))
+ ++n1;
+ }
+ else do
+ *x1++ = *x++;
+ while(x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+}
+
+/* Do a three-way compare of a and b, returning -1 if a < b, 0 if a == b and
+ 1 if a > b. Ignores signs of a and b. */
+
+static int
+cmp(Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for(;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+/* Take the difference of Bigints a and b, returning a new Bigint. Returns
+ NULL on failure. The signs of a and b are ignored, but the sign of the
+ result is set appropriately. */
+
+static Bigint *
+diff(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+ ULong z;
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ if (c == NULL)
+ return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ if (c == NULL)
+ return NULL;
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ }
+#else
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#endif
+ while(!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+/* Given a positive normal double x, return the difference between x and the
+ next double up. Doesn't give correct results for subnormals. */
+
+static double
+ulp(U *x)
+{
+ Long L;
+ U u;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+ word0(&u) = L;
+ word1(&u) = 0;
+ return dval(&u);
+}
+
+/* Convert a Bigint to a double plus an exponent */
+
+static double
+b2d(Bigint *a, int *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ U d;
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+ if (k < Ebits) {
+ word0(&d) = Exp_1 | y >> (Ebits - k);
+ w = xa > xa0 ? *--xa : 0;
+ word1(&d) = y << ((32-Ebits) + k) | w >> (Ebits - k);
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ word0(&d) = Exp_1 | y << k | z >> (32 - k);
+ y = xa > xa0 ? *--xa : 0;
+ word1(&d) = z << k | y >> (32 - k);
+ }
+ else {
+ word0(&d) = Exp_1 | y;
+ word1(&d) = z;
+ }
+ ret_d:
+ return dval(&d);
+}
+
+/* Convert a scaled double to a Bigint plus an exponent. Similar to d2b,
+ except that it accepts the scale parameter used in _Py_dg_strtod (which
+ should be either 0 or 2*P), and the normalization for the return value is
+ different (see below). On input, d should be finite and nonnegative, and d
+ / 2**scale should be exactly representable as an IEEE 754 double.
+
+ Returns a Bigint b and an integer e such that
+
+ dval(d) / 2**scale = b * 2**e.
+
+ Unlike d2b, b is not necessarily odd: b and e are normalized so
+ that either 2**(P-1) <= b < 2**P and e >= Etiny, or b < 2**P
+ and e == Etiny. This applies equally to an input of 0.0: in that
+ case the return values are b = 0 and e = Etiny.
+
+ The above normalization ensures that for all possible inputs d,
+ 2**e gives ulp(d/2**scale).
+
+ Returns NULL on failure.
+*/
+
+static Bigint *
+sd2b(U *d, int scale, int *e)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ if (b == NULL)
+ return NULL;
+
+ /* First construct b and e assuming that scale == 0. */
+ b->wds = 2;
+ b->x[0] = word1(d);
+ b->x[1] = word0(d) & Frac_mask;
+ *e = Etiny - 1 + (int)((word0(d) & Exp_mask) >> Exp_shift);
+ if (*e < Etiny)
+ *e = Etiny;
+ else
+ b->x[1] |= Exp_msk1;
+
+ /* Now adjust for scale, provided that b != 0. */
+ if (scale && (b->x[0] || b->x[1])) {
+ *e -= scale;
+ if (*e < Etiny) {
+ scale = Etiny - *e;
+ *e = Etiny;
+ /* We can't shift more than P-1 bits without shifting out a 1. */
+ assert(0 < scale && scale <= P - 1);
+ if (scale >= 32) {
+ /* The bits shifted out should all be zero. */
+ assert(b->x[0] == 0);
+ b->x[0] = b->x[1];
+ b->x[1] = 0;
+ scale -= 32;
+ }
+ if (scale) {
+ /* The bits shifted out should all be zero. */
+ assert(b->x[0] << (32 - scale) == 0);
+ b->x[0] = (b->x[0] >> scale) | (b->x[1] << (32 - scale));
+ b->x[1] >>= scale;
+ }
+ }
+ }
+ /* Ensure b is normalized. */
+ if (!b->x[1])
+ b->wds = 1;
+
+ return b;
+}
+
+/* Convert a double to a Bigint plus an exponent. Return NULL on failure.
+
+ Given a finite nonzero double d, return an odd Bigint b and exponent *e
+ such that fabs(d) = b * 2**e. On return, *bbits gives the number of
+ significant bits of b; that is, 2**(*bbits-1) <= b < 2**(*bbits).
+
+ If d is zero, then b == 0, *e == -1010, *bbits = 0.
+ */
+
+static Bigint *
+d2b(U *d, int *e, int *bits)
+{
+ Bigint *b;
+ int de, k;
+ ULong *x, y, z;
+ int i;
+
+ b = Balloc(1);
+ if (b == NULL)
+ return NULL;
+ x = b->x;
+
+ z = word0(d) & Frac_mask;
+ word0(d) &= 0x7fffffff; /* clear sign bit, which we ignore */
+ if ((de = (int)(word0(d) >> Exp_shift)))
+ z |= Exp_msk1;
+ if ((y = word1(d))) {
+ if ((k = lo0bits(&y))) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ }
+ else
+ x[0] = y;
+ i =
+ b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+ k = lo0bits(&z);
+ x[0] = z;
+ i =
+ b->wds = 1;
+ k += 32;
+ }
+ if (de) {
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+ *bits = 32*i - hi0bits(x[i-1]);
+ }
+ return b;
+}
+
+/* Compute the ratio of two Bigints, as a double. The result may have an
+ error of up to 2.5 ulps. */
+
+static double
+ratio(Bigint *a, Bigint *b)
+{
+ U da, db;
+ int k, ka, kb;
+
+ dval(&da) = b2d(a, &ka);
+ dval(&db) = b2d(b, &kb);
+ k = ka - kb + 32*(a->wds - b->wds);
+ if (k > 0)
+ word0(&da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(&db) += k*Exp_msk1;
+ }
+ return dval(&da) / dval(&db);
+}
+
+static const double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+};
+
+static const double
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+ 9007199254740992.*9007199254740992.e-256
+ /* = 2^106 * 1e-256 */
+};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+
+
+static int
+dshift(Bigint *b, int p2)
+{
+ int rv = hi0bits(b->x[b->wds-1]) - 4;
+ if (p2 > 0)
+ rv -= p2;
+ return rv & kmask;
+}
+
+/* special case of Bigint division. The quotient is always in the range 0 <=
+ quotient < 10, and on entry the divisor S is normalized so that its top 4
+ bits (28--31) are zero and bit 27 is set. */
+
+static int
+quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+ ULong si, z, zs;
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#endif
+ }
+ while(sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#endif
+ }
+ while(sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+/* sulp(x) is a version of ulp(x) that takes bc.scale into account.
+
+ Assuming that x is finite and nonnegative (positive zero is fine
+ here) and x / 2^bc.scale is exactly representable as a double,
+ sulp(x) is equivalent to 2^bc.scale * ulp(x / 2^bc.scale). */
+
+static double
+sulp(U *x, BCinfo *bc)
+{
+ U u;
+
+ if (bc->scale && 2*P + 1 > (int)((word0(x) & Exp_mask) >> Exp_shift)) {
+ /* rv/2^bc->scale is subnormal */
+ word0(&u) = (P+2)*Exp_msk1;
+ word1(&u) = 0;
+ return u.d;
+ }
+ else {
+ assert(word0(x) || word1(x)); /* x != 0.0 */
+ return ulp(x);
+ }
+}
+
+/* The bigcomp function handles some hard cases for strtod, for inputs
+ with more than STRTOD_DIGLIM digits. It's called once an initial
+ estimate for the double corresponding to the input string has
+ already been obtained by the code in _Py_dg_strtod.
+
+ The bigcomp function is only called after _Py_dg_strtod has found a
+ double value rv such that either rv or rv + 1ulp represents the
+ correctly rounded value corresponding to the original string. It
+ determines which of these two values is the correct one by
+ computing the decimal digits of rv + 0.5ulp and comparing them with
+ the corresponding digits of s0.
+
+ In the following, write dv for the absolute value of the number represented
+ by the input string.
+
+ Inputs:
+
+ s0 points to the first significant digit of the input string.
+
+ rv is a (possibly scaled) estimate for the closest double value to the
+ value represented by the original input to _Py_dg_strtod. If
+ bc->scale is nonzero, then rv/2^(bc->scale) is the approximation to
+ the input value.
+
+ bc is a struct containing information gathered during the parsing and
+ estimation steps of _Py_dg_strtod. Description of fields follows:
+
+ bc->e0 gives the exponent of the input value, such that dv = (integer
+ given by the bd->nd digits of s0) * 10**e0
+
+ bc->nd gives the total number of significant digits of s0. It will
+ be at least 1.
+
+ bc->nd0 gives the number of significant digits of s0 before the
+ decimal separator. If there's no decimal separator, bc->nd0 ==
+ bc->nd.
+
+ bc->scale is the value used to scale rv to avoid doing arithmetic with
+ subnormal values. It's either 0 or 2*P (=106).
+
+ Outputs:
+
+ On successful exit, rv/2^(bc->scale) is the closest double to dv.
+
+ Returns 0 on success, -1 on failure (e.g., due to a failed malloc call). */
+
+static int
+bigcomp(U *rv, const char *s0, BCinfo *bc)
+{
+ Bigint *b, *d;
+ int b2, d2, dd, i, nd, nd0, odd, p2, p5;
+
+ nd = bc->nd;
+ nd0 = bc->nd0;
+ p5 = nd + bc->e0;
+ b = sd2b(rv, bc->scale, &p2);
+ if (b == NULL)
+ return -1;
+
+ /* record whether the lsb of rv/2^(bc->scale) is odd: in the exact halfway
+ case, this is used for round to even. */
+ odd = b->x[0] & 1;
+
+ /* left shift b by 1 bit and or a 1 into the least significant bit;
+ this gives us b * 2**p2 = rv/2^(bc->scale) + 0.5 ulp. */
+ b = lshift(b, 1);
+ if (b == NULL)
+ return -1;
+ b->x[0] |= 1;
+ p2--;
+
+ p2 -= p5;
+ d = i2b(1);
+ if (d == NULL) {
+ Bfree(b);
+ return -1;
+ }
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ */
+ if (p5 > 0) {
+ d = pow5mult(d, p5);
+ if (d == NULL) {
+ Bfree(b);
+ return -1;
+ }
+ }
+ else if (p5 < 0) {
+ b = pow5mult(b, -p5);
+ if (b == NULL) {
+ Bfree(d);
+ return -1;
+ }
+ }
+ if (p2 > 0) {
+ b2 = p2;
+ d2 = 0;
+ }
+ else {
+ b2 = 0;
+ d2 = -p2;
+ }
+ i = dshift(d, d2);
+ if ((b2 += i) > 0) {
+ b = lshift(b, b2);
+ if (b == NULL) {
+ Bfree(d);
+ return -1;
+ }
+ }
+ if ((d2 += i) > 0) {
+ d = lshift(d, d2);
+ if (d == NULL) {
+ Bfree(b);
+ return -1;
+ }
+ }
+
+ /* Compare s0 with b/d: set dd to -1, 0, or 1 according as s0 < b/d, s0 ==
+ * b/d, or s0 > b/d. Here the digits of s0 are thought of as representing
+ * a number in the range [0.1, 1). */
+ if (cmp(b, d) >= 0)
+ /* b/d >= 1 */
+ dd = -1;
+ else {
+ i = 0;
+ for(;;) {
+ b = multadd(b, 10, 0);
+ if (b == NULL) {
+ Bfree(d);
+ return -1;
+ }
+ dd = s0[i < nd0 ? i : i+1] - '0' - quorem(b, d);
+ i++;
+
+ if (dd)
+ break;
+ if (!b->x[0] && b->wds == 1) {
+ /* b/d == 0 */
+ dd = i < nd;
+ break;
+ }
+ if (!(i < nd)) {
+ /* b/d != 0, but digits of s0 exhausted */
+ dd = -1;
+ break;
+ }
+ }
+ }
+ Bfree(b);
+ Bfree(d);
+ if (dd > 0 || (dd == 0 && odd))
+ dval(rv) += sulp(rv, bc);
+ return 0;
+}
+
+double
+_Py_dg_strtod(const char *s00, char **se)
+{
+ int bb2, bb5, bbe, bd2, bd5, bs2, c, dsign, e, e1, error;
+ int esign, i, j, k, lz, nd, nd0, odd, sign;
+ const char *s, *s0, *s1;
+ double aadj, aadj1;
+ U aadj2, adj, rv, rv0;
+ ULong y, z, abs_exp;
+ Long L;
+ BCinfo bc;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+ size_t ndigits, fraclen;
+
+ dval(&rv) = 0.;
+
+ /* Start parsing. */
+ c = *(s = s00);
+
+ /* Parse optional sign, if present. */
+ sign = 0;
+ switch (c) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ c = *++s;
+ }
+
+ /* Skip leading zeros: lz is true iff there were leading zeros. */
+ s1 = s;
+ while (c == '0')
+ c = *++s;
+ lz = s != s1;
+
+ /* Point s0 at the first nonzero digit (if any). fraclen will be the
+ number of digits between the decimal point and the end of the
+ digit string. ndigits will be the total number of digits ignoring
+ leading zeros. */
+ s0 = s1 = s;
+ while ('0' <= c && c <= '9')
+ c = *++s;
+ ndigits = s - s1;
+ fraclen = 0;
+
+ /* Parse decimal point and following digits. */
+ if (c == '.') {
+ c = *++s;
+ if (!ndigits) {
+ s1 = s;
+ while (c == '0')
+ c = *++s;
+ lz = lz || s != s1;
+ fraclen += (s - s1);
+ s0 = s;
+ }
+ s1 = s;
+ while ('0' <= c && c <= '9')
+ c = *++s;
+ ndigits += s - s1;
+ fraclen += s - s1;
+ }
+
+ /* Now lz is true if and only if there were leading zero digits, and
+ ndigits gives the total number of digits ignoring leading zeros. A
+ valid input must have at least one digit. */
+ if (!ndigits && !lz) {
+ if (se)
+ *se = (char *)s00;
+ goto parse_error;
+ }
+
+ /* Range check ndigits and fraclen to make sure that they, and values
+ computed with them, can safely fit in an int. */
+ if (ndigits > MAX_DIGITS || fraclen > MAX_DIGITS) {
+ if (se)
+ *se = (char *)s00;
+ goto parse_error;
+ }
+ nd = (int)ndigits;
+ nd0 = (int)ndigits - (int)fraclen;
+
+ /* Parse exponent. */
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ s00 = s;
+ c = *++s;
+
+ /* Exponent sign. */
+ esign = 0;
+ switch (c) {
+ case '-':
+ esign = 1;
+ /* no break */
+ case '+':
+ c = *++s;
+ }
+
+ /* Skip zeros. lz is true iff there are leading zeros. */
+ s1 = s;
+ while (c == '0')
+ c = *++s;
+ lz = s != s1;
+
+ /* Get absolute value of the exponent. */
+ s1 = s;
+ abs_exp = 0;
+ while ('0' <= c && c <= '9') {
+ abs_exp = 10*abs_exp + (c - '0');
+ c = *++s;
+ }
+
+ /* abs_exp will be correct modulo 2**32. But 10**9 < 2**32, so if
+ there are at most 9 significant exponent digits then overflow is
+ impossible. */
+ if (s - s1 > 9 || abs_exp > MAX_ABS_EXP)
+ e = (int)MAX_ABS_EXP;
+ else
+ e = (int)abs_exp;
+ if (esign)
+ e = -e;
+
+ /* A valid exponent must have at least one digit. */
+ if (s == s1 && !lz)
+ s = s00;
+ }
+
+ /* Adjust exponent to take into account position of the point. */
+ e -= nd - nd0;
+ if (nd0 <= 0)
+ nd0 = nd;
+
+ /* Finished parsing. Set se to indicate how far we parsed */
+ if (se)
+ *se = (char *)s;
+
+ /* If all digits were zero, exit with return value +-0.0. Otherwise,
+ strip trailing zeros: scan back until we hit a nonzero digit. */
+ if (!nd)
+ goto ret;
+ for (i = nd; i > 0; ) {
+ --i;
+ if (s0[i < nd0 ? i : i+1] != '0') {
+ ++i;
+ break;
+ }
+ }
+ e += nd - i;
+ nd = i;
+ if (nd0 > nd)
+ nd0 = nd;
+
+ /* Summary of parsing results. After parsing, and dealing with zero
+ * inputs, we have values s0, nd0, nd, e, sign, where:
+ *
+ * - s0 points to the first significant digit of the input string
+ *
+ * - nd is the total number of significant digits (here, and
+ * below, 'significant digits' means the set of digits of the
+ * significand of the input that remain after ignoring leading
+ * and trailing zeros).
+ *
+ * - nd0 indicates the position of the decimal point, if present; it
+ * satisfies 1 <= nd0 <= nd. The nd significant digits are in
+ * s0[0:nd0] and s0[nd0+1:nd+1] using the usual Python half-open slice
+ * notation. (If nd0 < nd, then s0[nd0] contains a '.' character; if
+ * nd0 == nd, then s0[nd0] could be any non-digit character.)
+ *
+ * - e is the adjusted exponent: the absolute value of the number
+ * represented by the original input string is n * 10**e, where
+ * n is the integer represented by the concatenation of
+ * s0[0:nd0] and s0[nd0+1:nd+1]
+ *
+ * - sign gives the sign of the input: 1 for negative, 0 for positive
+ *
+ * - the first and last significant digits are nonzero
+ */
+
+ /* put first DBL_DIG+1 digits into integer y and z.
+ *
+ * - y contains the value represented by the first min(9, nd)
+ * significant digits
+ *
+ * - if nd > 9, z contains the value represented by significant digits
+ * with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z
+ * gives the value represented by the first min(16, nd) sig. digits.
+ */
+
+ bc.e0 = e1 = e;
+ y = z = 0;
+ for (i = 0; i < nd; i++) {
+ if (i < 9)
+ y = 10*y + s0[i < nd0 ? i : i+1] - '0';
+ else if (i < DBL_DIG+1)
+ z = 10*z + s0[i < nd0 ? i : i+1] - '0';
+ else
+ break;
+ }
+
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ dval(&rv) = y;
+ if (k > 9) {
+ dval(&rv) = tens[k - 9] * dval(&rv) + z;
+ }
+ bd0 = 0;
+ if (nd <= DBL_DIG
+ && Flt_Rounds == 1
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+ dval(&rv) *= tens[e];
+ goto ret;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ dval(&rv) *= tens[i];
+ dval(&rv) *= tens[e];
+ goto ret;
+ }
+ }
+ else if (e >= -Ten_pmax) {
+ dval(&rv) /= tens[-e];
+ goto ret;
+ }
+ }
+ e1 += nd - k;
+
+ bc.scale = 0;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15))
+ dval(&rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP)
+ goto ovfl;
+ e1 >>= 4;
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(&rv) -= P*Exp_msk1;
+ dval(&rv) *= bigtens[j];
+ if ((z = word0(&rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ }
+ else
+ word0(&rv) += P*Exp_msk1;
+ }
+ }
+ else if (e1 < 0) {
+ /* The input decimal value lies in [10**e1, 10**(e1+16)).
+
+ If e1 <= -512, underflow immediately.
+ If e1 <= -256, set bc.scale to 2*P.
+
+ So for input value < 1e-256, bc.scale is always set;
+ for input value >= 1e-240, bc.scale is never set.
+ For input values in [1e-256, 1e-240), bc.scale may or may
+ not be set. */
+
+ e1 = -e1;
+ if ((i = e1 & 15))
+ dval(&rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+ if (e1 & Scale_Bit)
+ bc.scale = 2*P;
+ for(j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= tinytens[j];
+ if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)
+ >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; clear j low bits */
+ if (j >= 32) {
+ word1(&rv) = 0;
+ if (j >= 53)
+ word0(&rv) = (P+2)*Exp_msk1;
+ else
+ word0(&rv) &= 0xffffffff << (j-32);
+ }
+ else
+ word1(&rv) &= 0xffffffff << j;
+ }
+ if (!dval(&rv))
+ goto undfl;
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bc.nd = nd;
+ bc.nd0 = nd0; /* Only needed if nd > STRTOD_DIGLIM, but done here */
+ /* to silence an erroneous warning about bc.nd0 */
+ /* possibly not being initialized. */
+ if (nd > STRTOD_DIGLIM) {
+ /* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */
+ /* minimum number of decimal digits to distinguish double values */
+ /* in IEEE arithmetic. */
+
+ /* Truncate input to 18 significant digits, then discard any trailing
+ zeros on the result by updating nd, nd0, e and y suitably. (There's
+ no need to update z; it's not reused beyond this point.) */
+ for (i = 18; i > 0; ) {
+ /* scan back until we hit a nonzero digit. significant digit 'i'
+ is s0[i] if i < nd0, s0[i+1] if i >= nd0. */
+ --i;
+ if (s0[i < nd0 ? i : i+1] != '0') {
+ ++i;
+ break;
+ }
+ }
+ e += nd - i;
+ nd = i;
+ if (nd0 > nd)
+ nd0 = nd;
+ if (nd < 9) { /* must recompute y */
+ y = 0;
+ for(i = 0; i < nd0; ++i)
+ y = 10*y + s0[i] - '0';
+ for(; i < nd; ++i)
+ y = 10*y + s0[i+1] - '0';
+ }
+ }
+ bd0 = s2b(s0, nd0, nd, y);
+ if (bd0 == NULL)
+ goto failed_malloc;
+
+ /* Notation for the comments below. Write:
+
+ - dv for the absolute value of the number represented by the original
+ decimal input string.
+
+ - if we've truncated dv, write tdv for the truncated value.
+ Otherwise, set tdv == dv.
+
+ - srv for the quantity rv/2^bc.scale; so srv is the current binary
+ approximation to tdv (and dv). It should be exactly representable
+ in an IEEE 754 double.
+ */
+
+ for(;;) {
+
+ /* This is the main correction loop for _Py_dg_strtod.
+
+ We've got a decimal value tdv, and a floating-point approximation
+ srv=rv/2^bc.scale to tdv. The aim is to determine whether srv is
+ close enough (i.e., within 0.5 ulps) to tdv, and to compute a new
+ approximation if not.
+
+ To determine whether srv is close enough to tdv, compute integers
+ bd, bb and bs proportional to tdv, srv and 0.5 ulp(srv)
+ respectively, and then use integer arithmetic to determine whether
+ |tdv - srv| is less than, equal to, or greater than 0.5 ulp(srv).
+ */
+
+ bd = Balloc(bd0->k);
+ if (bd == NULL) {
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ Bcopy(bd, bd0);
+ bb = sd2b(&rv, bc.scale, &bbe); /* srv = bb * 2^bbe */
+ if (bb == NULL) {
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ /* Record whether lsb of bb is odd, in case we need this
+ for the round-to-even step later. */
+ odd = bb->x[0] & 1;
+
+ /* tdv = bd * 10**e; srv = bb * 2**bbe */
+ bs = i2b(1);
+ if (bs == NULL) {
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+ bb2++;
+ bd2++;
+
+ /* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1,
+ and bs == 1, so:
+
+ tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5)
+ srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2)
+ 0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2)
+
+ It follows that:
+
+ M * tdv = bd * 2**bd2 * 5**bd5
+ M * srv = bb * 2**bb2 * 5**bb5
+ M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5
+
+ for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but
+ this fact is not needed below.)
+ */
+
+ /* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+
+ /* Scale bb, bd, bs by the appropriate powers of 2 and 5. */
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ if (bs == NULL) {
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ if (bb == NULL) {
+ Bfree(bs);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ }
+ if (bb2 > 0) {
+ bb = lshift(bb, bb2);
+ if (bb == NULL) {
+ Bfree(bs);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ }
+ if (bd5 > 0) {
+ bd = pow5mult(bd, bd5);
+ if (bd == NULL) {
+ Bfree(bb);
+ Bfree(bs);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ }
+ if (bd2 > 0) {
+ bd = lshift(bd, bd2);
+ if (bd == NULL) {
+ Bfree(bb);
+ Bfree(bs);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ }
+ if (bs2 > 0) {
+ bs = lshift(bs, bs2);
+ if (bs == NULL) {
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ }
+
+ /* Now bd, bb and bs are scaled versions of tdv, srv and 0.5 ulp(srv),
+ respectively. Compute the difference |tdv - srv|, and compare
+ with 0.5 ulp(srv). */
+
+ delta = diff(bb, bd);
+ if (delta == NULL) {
+ Bfree(bb);
+ Bfree(bs);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+ if (bc.nd > nd && i <= 0) {
+ if (dsign)
+ break; /* Must use bigcomp(). */
+
+ /* Here rv overestimates the truncated decimal value by at most
+ 0.5 ulp(rv). Hence rv either overestimates the true decimal
+ value by <= 0.5 ulp(rv), or underestimates it by some small
+ amount (< 0.1 ulp(rv)); either way, rv is within 0.5 ulps of
+ the true decimal value, so it's possible to exit.
+
+ Exception: if scaled rv is a normal exact power of 2, but not
+ DBL_MIN, then rv - 0.5 ulp(rv) takes us all the way down to the
+ next double, so the correctly rounded result is either rv - 0.5
+ ulp(rv) or rv; in this case, use bigcomp to distinguish. */
+
+ if (!word1(&rv) && !(word0(&rv) & Bndry_mask)) {
+ /* rv can't be 0, since it's an overestimate for some
+ nonzero value. So rv is a normal power of 2. */
+ j = (int)(word0(&rv) & Exp_mask) >> Exp_shift;
+ /* rv / 2^bc.scale = 2^(j - 1023 - bc.scale); use bigcomp if
+ rv / 2^bc.scale >= 2^-1021. */
+ if (j - bc.scale >= 2) {
+ dval(&rv) -= 0.5 * sulp(&rv, &bc);
+ break; /* Use bigcomp. */
+ }
+ }
+
+ {
+ bc.nd = nd;
+ i = -1; /* Discarded digits make delta smaller. */
+ }
+ }
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask
+ || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+ ) {
+ break;
+ }
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact result */
+ break;
+ }
+ delta = lshift(delta,Log2P);
+ if (delta == NULL) {
+ Bfree(bb);
+ Bfree(bs);
+ Bfree(bd);
+ Bfree(bd0);
+ goto failed_malloc;
+ }
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+ && word1(&rv) == (
+ (bc.scale &&
+ (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) ?
+ (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ word0(&rv) = (word0(&rv) & Exp_mask)
+ + Exp_msk1
+ ;
+ word1(&rv) = 0;
+ dsign = 0;
+ break;
+ }
+ }
+ else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+ drop_down:
+ /* boundary case -- decrement exponent */
+ if (bc.scale) {
+ L = word0(&rv) & Exp_mask;
+ if (L <= (2*P+1)*Exp_msk1) {
+ if (L > (P+2)*Exp_msk1)
+ /* round even ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest denormal */
+ if (bc.nd > nd)
+ break;
+ goto undfl;
+ }
+ }
+ L = (word0(&rv) & Exp_mask) - Exp_msk1;
+ word0(&rv) = L | Bndry_mask1;
+ word1(&rv) = 0xffffffff;
+ break;
+ }
+ if (!odd)
+ break;
+ if (dsign)
+ dval(&rv) += sulp(&rv, &bc);
+ else {
+ dval(&rv) -= sulp(&rv, &bc);
+ if (!dval(&rv)) {
+ if (bc.nd >nd)
+ break;
+ goto undfl;
+ }
+ }
+ dsign = 1 - dsign;
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+ if (word1(&rv) == Tiny1 && !word0(&rv)) {
+ if (bc.nd >nd)
+ break;
+ goto undfl;
+ }
+ aadj = 1.;
+ aadj1 = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+ if (Flt_Rounds == 0)
+ aadj1 += 0.5;
+ }
+ y = word0(&rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ dval(&rv0) = dval(&rv);
+ word0(&rv) -= P*Exp_msk1;
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ if ((word0(&rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(&rv0) == Big0 && word1(&rv0) == Big1) {
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ goto ovfl;
+ }
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ goto cont;
+ }
+ else
+ word0(&rv) += P*Exp_msk1;
+ }
+ else {
+ if (bc.scale && y <= 2*P*Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (ULong)aadj) <= 0)
+ z = 1;
+ aadj = z;
+ aadj1 = dsign ? aadj : -aadj;
+ }
+ dval(&aadj2) = aadj1;
+ word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
+ aadj1 = dval(&aadj2);
+ }
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ }
+ z = word0(&rv) & Exp_mask;
+ if (bc.nd == nd) {
+ if (!bc.scale)
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+ }
+ cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ if (bc.nd > nd) {
+ error = bigcomp(&rv, s0, &bc);
+ if (error)
+ goto failed_malloc;
+ }
+
+ if (bc.scale) {
+ word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
+ word1(&rv0) = 0;
+ dval(&rv) *= dval(&rv0);
+ }
+
+ ret:
+ return sign ? -dval(&rv) : dval(&rv);
+
+ parse_error:
+ return 0.0;
+
+ failed_malloc:
+ errno = ENOMEM;
+ return -1.0;
+
+ undfl:
+ return sign ? -0.0 : 0.0;
+
+ ovfl:
+ errno = ERANGE;
+ /* Can't trust HUGE_VAL */
+ word0(&rv) = Exp_mask;
+ word1(&rv) = 0;
+ return sign ? -dval(&rv) : dval(&rv);
+
+}
+
+static char *
+rv_alloc(int i)
+{
+ int j, k, *r;
+
+ j = sizeof(ULong);
+ for(k = 0;
+ sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned)i;
+ j <<= 1)
+ k++;
+ r = (int*)Balloc(k);
+ if (r == NULL)
+ return NULL;
+ *r = k;
+ return (char *)(r+1);
+}
+
+static char *
+nrv_alloc(char *s, char **rve, int n)
+{
+ char *rv, *t;
+
+ rv = rv_alloc(n);
+ if (rv == NULL)
+ return NULL;
+ t = rv;
+ while((*t = *s++)) t++;
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+void
+_Py_dg_freedtoa(char *s)
+{
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+/* Additional notes (METD): (1) returns NULL on failure. (2) to avoid memory
+ leakage, a successful call to _Py_dg_dtoa should always be matched by a
+ call to _Py_dg_freedtoa. */
+
+char *
+_Py_dg_dtoa(double dd, int mode, int ndigits,
+ int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ Long L;
+ int denorm;
+ ULong x;
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+ U d2, eps, u;
+ double ds;
+ char *s, *s0;
+
+ /* set pointers to NULL, to silence gcc compiler warnings and make
+ cleanup easier on error */
+ mlo = mhi = S = 0;
+ s0 = 0;
+
+ u.d = dd;
+ if (word0(&u) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(&u) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+ /* quick return for Infinities, NaNs and zeros */
+ if ((word0(&u) & Exp_mask) == Exp_mask)
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ if (!word1(&u) && !(word0(&u) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+ return nrv_alloc("NaN", rve, 3);
+ }
+ if (!dval(&u)) {
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+ /* compute k = floor(log10(d)). The computation may leave k
+ one too large, but should never leave k too small. */
+ b = d2b(&u, &be, &bbits);
+ if (b == NULL)
+ goto failed_malloc;
+ if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
+ dval(&d2) = dval(&u);
+ word0(&d2) &= Frac_mask1;
+ word0(&d2) |= Exp_11;
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32)
+ : word1(&u) << (32 - i);
+ dval(&d2) = x;
+ word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+ ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 +
+ i*0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(&u) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+ try_quick = 1;
+
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
+ /* silence erroneous "gcc -Wall" warning. */
+ switch(mode) {
+ case 0:
+ case 1:
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s0 = rv_alloc(i);
+ if (s0 == NULL)
+ goto failed_malloc;
+ s = s0;
+
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(&d2) = dval(&u);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(&u) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(&u) /= ds;
+ }
+ else if ((j1 = -k)) {
+ dval(&u) *= tens[j1 & 0xf];
+ for(j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(&u) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(&u) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(&u) *= 10.;
+ ieps++;
+ }
+ dval(&eps) = ieps*dval(&u) + 7.;
+ word0(&eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(&u) -= 5.;
+ if (dval(&u) > dval(&eps))
+ goto one_digit;
+ if (dval(&u) < -dval(&eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+ for(i = 0;;) {
+ L = (Long)dval(&u);
+ dval(&u) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(&u) < dval(&eps))
+ goto ret1;
+ if (1. - dval(&u) < dval(&eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(&eps) *= 10.;
+ dval(&u) *= 10.;
+ }
+ }
+ else {
+ /* Generate ilim digits, then fix them up. */
+ dval(&eps) *= tens[ilim-1];
+ for(i = 1;; i++, dval(&u) *= 10.) {
+ L = (Long)(dval(&u));
+ if (!(dval(&u) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(&u) > 0.5 + dval(&eps))
+ goto bump_up;
+ else if (dval(&u) < 0.5 - dval(&eps)) {
+ while(*--s == '0');
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+ }
+ fast_failed:
+ s = s0;
+ dval(&u) = dval(&d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(&u) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++, dval(&u) *= 10.) {
+ L = (Long)(dval(&u) / ds);
+ dval(&u) -= L*ds;
+ *s++ = '0' + (int)L;
+ if (!dval(&u)) {
+ break;
+ }
+ if (i == ilim) {
+ dval(&u) += dval(&u);
+ if (dval(&u) > ds || (dval(&u) == ds && L & 1)) {
+ bump_up:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ if (leftright) {
+ i =
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+ 1 + P - bbits;
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ if (mhi == NULL)
+ goto failed_malloc;
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ if (mhi == NULL)
+ goto failed_malloc;
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ if (b == NULL)
+ goto failed_malloc;
+ }
+ if ((j = b5 - m5)) {
+ b = pow5mult(b, j);
+ if (b == NULL)
+ goto failed_malloc;
+ }
+ }
+ else {
+ b = pow5mult(b, b5);
+ if (b == NULL)
+ goto failed_malloc;
+ }
+ }
+ S = i2b(1);
+ if (S == NULL)
+ goto failed_malloc;
+ if (s5 > 0) {
+ S = pow5mult(S, s5);
+ if (S == NULL)
+ goto failed_malloc;
+ }
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((mode < 2 || leftright)
+ ) {
+ if (!word1(&u) && !(word0(&u) & Bndry_mask)
+ && word0(&u) & (Exp_mask & ~Exp_msk1)
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#define iInc 28
+ i = dshift(S, s2);
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ if (b2 > 0) {
+ b = lshift(b, b2);
+ if (b == NULL)
+ goto failed_malloc;
+ }
+ if (s2 > 0) {
+ S = lshift(S, s2);
+ if (S == NULL)
+ goto failed_malloc;
+ }
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (b == NULL)
+ goto failed_malloc;
+ if (leftright) {
+ mhi = multadd(mhi, 10, 0);
+ if (mhi == NULL)
+ goto failed_malloc;
+ }
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0) {
+ /* no digits, fcvt style */
+ no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+ else {
+ S = multadd(S, 5, 0);
+ if (S == NULL)
+ goto failed_malloc;
+ if (cmp(b, S) <= 0)
+ goto no_digits;
+ }
+ one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0) {
+ mhi = lshift(mhi, m2);
+ if (mhi == NULL)
+ goto failed_malloc;
+ }
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ if (mhi == NULL)
+ goto failed_malloc;
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ if (mhi == NULL)
+ goto failed_malloc;
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ if (delta == NULL)
+ goto failed_malloc;
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+ if (j1 == 0 && mode != 1 && !(word1(&u) & 1)
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+ *s++ = dig;
+ goto ret;
+ }
+ if (j < 0 || (j == 0 && mode != 1
+ && !(word1(&u) & 1)
+ )) {
+ if (!b->x[0] && b->wds <= 1) {
+ goto accept_dig;
+ }
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ if (b == NULL)
+ goto failed_malloc;
+ j1 = cmp(b, S);
+ if ((j1 > 0 || (j1 == 0 && dig & 1))
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (b == NULL)
+ goto failed_malloc;
+ if (mlo == mhi) {
+ mlo = mhi = multadd(mhi, 10, 0);
+ if (mlo == NULL)
+ goto failed_malloc;
+ }
+ else {
+ mlo = multadd(mlo, 10, 0);
+ if (mlo == NULL)
+ goto failed_malloc;
+ mhi = multadd(mhi, 10, 0);
+ if (mhi == NULL)
+ goto failed_malloc;
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (!b->x[0] && b->wds <= 1) {
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (b == NULL)
+ goto failed_malloc;
+ }
+
+ /* Round off last digit */
+
+ b = lshift(b, 1);
+ if (b == NULL)
+ goto failed_malloc;
+ j = cmp(b, S);
+ if (j > 0 || (j == 0 && dig & 1)) {
+ roundoff:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+ while(*--s == '0');
+ s++;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+ failed_malloc:
+ if (S)
+ Bfree(S);
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ if (mhi)
+ Bfree(mhi);
+ if (b)
+ Bfree(b);
+ if (s0)
+ _Py_dg_freedtoa(s0);
+ return NULL;
+}
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PY_NO_SHORT_FLOAT_REPR */
diff --git a/contrib/tools/python/src/Python/dynload_shlib.c b/contrib/tools/python/src/Python/dynload_shlib.c
new file mode 100644
index 0000000000..17ebab16ba
--- /dev/null
+++ b/contrib/tools/python/src/Python/dynload_shlib.c
@@ -0,0 +1,143 @@
+
+/* Support for dynamic loading of extension modules */
+
+#include "Python.h"
+#include "importdl.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__NetBSD__)
+#include <sys/param.h>
+#if (NetBSD < 199712)
+#include <nlist.h>
+#include <link.h>
+#define dlerror() "error in dynamic linking"
+#endif
+#endif /* NetBSD */
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+#if defined(PYOS_OS2) && defined(PYCC_GCC)
+#include "dlfcn.h"
+#endif
+#endif
+
+#if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__)
+#define LEAD_UNDERSCORE "_"
+#else
+#define LEAD_UNDERSCORE ""
+#endif
+
+
+const struct filedescr _PyImport_DynLoadFiletab[] = {
+#ifdef __CYGWIN__
+ {".dll", "rb", C_EXTENSION},
+ {"module.dll", "rb", C_EXTENSION},
+#else
+#if defined(PYOS_OS2) && defined(PYCC_GCC)
+ {".pyd", "rb", C_EXTENSION},
+ {".dll", "rb", C_EXTENSION},
+#else
+#ifdef __VMS
+ {".exe", "rb", C_EXTENSION},
+ {".EXE", "rb", C_EXTENSION},
+ {"module.exe", "rb", C_EXTENSION},
+ {"MODULE.EXE", "rb", C_EXTENSION},
+#else
+ {".so", "rb", C_EXTENSION},
+ {"module.so", "rb", C_EXTENSION},
+#endif
+#endif
+#endif
+ {0, 0}
+};
+
+static struct {
+ dev_t dev;
+#ifdef __VMS
+ ino_t ino[3];
+#else
+ ino_t ino;
+#endif
+ void *handle;
+} handles[128];
+static int nhandles = 0;
+
+
+dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
+ const char *pathname, FILE *fp)
+{
+ dl_funcptr p;
+ void *handle;
+ char funcname[258];
+ char pathbuf[260];
+ int dlopenflags=0;
+
+ if (strchr(pathname, '/') == NULL) {
+ /* Prefix bare filename with "./" */
+ PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname);
+ pathname = pathbuf;
+ }
+
+ PyOS_snprintf(funcname, sizeof(funcname),
+ LEAD_UNDERSCORE "init%.200s", shortname);
+
+ if (fp != NULL) {
+ int i;
+ struct stat statb;
+ fstat(fileno(fp), &statb);
+ for (i = 0; i < nhandles; i++) {
+ if (statb.st_dev == handles[i].dev &&
+ statb.st_ino == handles[i].ino) {
+ p = (dl_funcptr) dlsym(handles[i].handle,
+ funcname);
+ return p;
+ }
+ }
+ if (nhandles < 128) {
+ handles[nhandles].dev = statb.st_dev;
+#ifdef __VMS
+ handles[nhandles].ino[0] = statb.st_ino[0];
+ handles[nhandles].ino[1] = statb.st_ino[1];
+ handles[nhandles].ino[2] = statb.st_ino[2];
+#else
+ handles[nhandles].ino = statb.st_ino;
+#endif
+ }
+ }
+
+#if !(defined(PYOS_OS2) && defined(PYCC_GCC))
+ dlopenflags = PyThreadState_GET()->interp->dlopenflags;
+#endif
+
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("dlopen(\"%s\", %x);\n", pathname,
+ dlopenflags);
+
+#ifdef __VMS
+ /* VMS currently don't allow a pathname, use a logical name instead */
+ /* Concatenate 'python_module_' and shortname */
+ /* so "import vms.bar" will use the logical python_module_bar */
+ /* As C module use only one name space this is probably not a */
+ /* important limitation */
+ PyOS_snprintf(pathbuf, sizeof(pathbuf), "python_module_%-.200s",
+ shortname);
+ pathname = pathbuf;
+#endif
+
+ handle = dlopen(pathname, dlopenflags);
+
+ if (handle == NULL) {
+ const char *error = dlerror();
+ if (error == NULL)
+ error = "unknown dlopen() error";
+ PyErr_SetString(PyExc_ImportError, error);
+ return NULL;
+ }
+ if (fp != NULL && nhandles < 128)
+ handles[nhandles++].handle = handle;
+ p = (dl_funcptr) dlsym(handle, funcname);
+ return p;
+}
diff --git a/contrib/tools/python/src/Python/dynload_win.c b/contrib/tools/python/src/Python/dynload_win.c
new file mode 100644
index 0000000000..db3b5a551b
--- /dev/null
+++ b/contrib/tools/python/src/Python/dynload_win.c
@@ -0,0 +1,280 @@
+
+/* Support for dynamic loading of extension modules */
+
+#include "Python.h"
+
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+#include <ctype.h>
+
+#include "importdl.h"
+#include <windows.h>
+
+#if defined(Py_ENABLE_SHARED)
+// "activation context" magic - see dl_nt.c...
+extern ULONG_PTR _Py_ActivateActCtx();
+void _Py_DeactivateActCtx(ULONG_PTR cookie);
+#endif
+
+const struct filedescr _PyImport_DynLoadFiletab[] = {
+#ifdef _DEBUG
+ {"_d.pyd", "rb", C_EXTENSION},
+#else
+ {".pyd", "rb", C_EXTENSION},
+#endif
+ {0, 0}
+};
+
+
+/* Case insensitive string compare, to avoid any dependencies on particular
+ C RTL implementations */
+
+static int strcasecmp (char *string1, char *string2)
+{
+ int first, second;
+
+ do {
+ first = tolower(*string1);
+ second = tolower(*string2);
+ string1++;
+ string2++;
+ } while (first && first == second);
+
+ return (first - second);
+}
+
+
+/* Function to return the name of the "python" DLL that the supplied module
+ directly imports. Looks through the list of imported modules and
+ returns the first entry that starts with "python" (case sensitive) and
+ is followed by nothing but numbers until the separator (period).
+
+ Returns a pointer to the import name, or NULL if no matching name was
+ located.
+
+ This function parses through the PE header for the module as loaded in
+ memory by the system loader. The PE header is accessed as documented by
+ Microsoft in the MSDN PE and COFF specification (2/99), and handles
+ both PE32 and PE32+. It only worries about the direct import table and
+ not the delay load import table since it's unlikely an extension is
+ going to be delay loading Python (after all, it's already loaded).
+
+ If any magic values are not found (e.g., the PE header or optional
+ header magic), then this function simply returns NULL. */
+
+#define DWORD_AT(mem) (*(DWORD *)(mem))
+#define WORD_AT(mem) (*(WORD *)(mem))
+
+static char *GetPythonImport (HINSTANCE hModule)
+{
+ unsigned char *dllbase, *import_data, *import_name;
+ DWORD pe_offset, opt_offset;
+ WORD opt_magic;
+ int num_dict_off, import_off;
+
+ /* Safety check input */
+ if (hModule == NULL) {
+ return NULL;
+ }
+
+ /* Module instance is also the base load address. First portion of
+ memory is the MS-DOS loader, which holds the offset to the PE
+ header (from the load base) at 0x3C */
+ dllbase = (unsigned char *)hModule;
+ pe_offset = DWORD_AT(dllbase + 0x3C);
+
+ /* The PE signature must be "PE\0\0" */
+ if (memcmp(dllbase+pe_offset,"PE\0\0",4)) {
+ return NULL;
+ }
+
+ /* Following the PE signature is the standard COFF header (20
+ bytes) and then the optional header. The optional header starts
+ with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
+ uses 64-bits for some fields). It might also be 0x107 for a ROM
+ image, but we don't process that here.
+
+ The optional header ends with a data dictionary that directly
+ points to certain types of data, among them the import entries
+ (in the second table entry). Based on the header type, we
+ determine offsets for the data dictionary count and the entry
+ within the dictionary pointing to the imports. */
+
+ opt_offset = pe_offset + 4 + 20;
+ opt_magic = WORD_AT(dllbase+opt_offset);
+ if (opt_magic == 0x10B) {
+ /* PE32 */
+ num_dict_off = 92;
+ import_off = 104;
+ } else if (opt_magic == 0x20B) {
+ /* PE32+ */
+ num_dict_off = 108;
+ import_off = 120;
+ } else {
+ /* Unsupported */
+ return NULL;
+ }
+
+ /* Now if an import table exists, offset to it and walk the list of
+ imports. The import table is an array (ending when an entry has
+ empty values) of structures (20 bytes each), which contains (at
+ offset 12) a relative address (to the module base) at which a
+ string constant holding the import name is located. */
+
+ if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) {
+ /* We have at least 2 tables - the import table is the second
+ one. But still it may be that the table size is zero */
+ if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD)))
+ return NULL;
+ import_data = dllbase + DWORD_AT(dllbase +
+ opt_offset +
+ import_off);
+ while (DWORD_AT(import_data)) {
+ import_name = dllbase + DWORD_AT(import_data+12);
+ if (strlen(import_name) >= 6 &&
+ !strncmp(import_name,"python",6)) {
+ char *pch;
+
+ /* Ensure python prefix is followed only
+ by numbers to the end of the basename */
+ pch = import_name + 6;
+#ifdef _DEBUG
+ while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') {
+#else
+ while (*pch && *pch != '.') {
+#endif
+ if (*pch >= '0' && *pch <= '9') {
+ pch++;
+ } else {
+ pch = NULL;
+ break;
+ }
+ }
+
+ if (pch) {
+ /* Found it - return the name */
+ return import_name;
+ }
+ }
+ import_data += 20;
+ }
+ }
+
+ return NULL;
+}
+
+
+dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
+ const char *pathname, FILE *fp)
+{
+ dl_funcptr p;
+ char funcname[258], *import_python;
+
+ PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname);
+
+ {
+ HINSTANCE hDLL = NULL;
+ char pathbuf[260];
+ LPTSTR dummy;
+ unsigned int old_mode;
+ ULONG_PTR cookie = 0;
+ /* We use LoadLibraryEx so Windows looks for dependent DLLs
+ in directory of pathname first. However, Windows95
+ can sometimes not work correctly unless the absolute
+ path is used. If GetFullPathName() fails, the LoadLibrary
+ will certainly fail too, so use its error code */
+
+ /* Don't display a message box when Python can't load a DLL */
+ old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ if (GetFullPathName(pathname,
+ sizeof(pathbuf),
+ pathbuf,
+ &dummy)) {
+#if defined(Py_ENABLE_SHARED)
+ ULONG_PTR cookie = _Py_ActivateActCtx();
+#endif
+ /* XXX This call doesn't exist in Windows CE */
+ hDLL = LoadLibraryEx(pathname, NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+#if defined(Py_ENABLE_SHARED)
+ _Py_DeactivateActCtx(cookie);
+#endif
+ }
+
+ /* restore old error mode settings */
+ SetErrorMode(old_mode);
+
+ if (hDLL==NULL){
+ char errBuf[256];
+ unsigned int errorCode;
+
+ /* Get an error string from Win32 error code */
+ char theInfo[256]; /* Pointer to error text
+ from system */
+ int theLength; /* Length of error text */
+
+ errorCode = GetLastError();
+
+ theLength = FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
+ NULL, /* message source */
+ errorCode, /* the message (error) ID */
+ 0, /* default language environment */
+ (LPTSTR) theInfo, /* the buffer */
+ sizeof(theInfo), /* the buffer size */
+ NULL); /* no additional format args. */
+
+ /* Problem: could not get the error message.
+ This should not happen if called correctly. */
+ if (theLength == 0) {
+ PyOS_snprintf(errBuf, sizeof(errBuf),
+ "DLL load failed with error code %d",
+ errorCode);
+ } else {
+ size_t len;
+ /* For some reason a \r\n
+ is appended to the text */
+ if (theLength >= 2 &&
+ theInfo[theLength-2] == '\r' &&
+ theInfo[theLength-1] == '\n') {
+ theLength -= 2;
+ theInfo[theLength] = '\0';
+ }
+ strcpy(errBuf, "DLL load failed: ");
+ len = strlen(errBuf);
+ strncpy(errBuf+len, theInfo,
+ sizeof(errBuf)-len);
+ errBuf[sizeof(errBuf)-1] = '\0';
+ }
+ PyErr_SetString(PyExc_ImportError, errBuf);
+ return NULL;
+ } else {
+ char buffer[256];
+
+#ifdef _DEBUG
+ PyOS_snprintf(buffer, sizeof(buffer), "python%d%d_d.dll",
+#else
+ PyOS_snprintf(buffer, sizeof(buffer), "python%d%d.dll",
+#endif
+ PY_MAJOR_VERSION,PY_MINOR_VERSION);
+ import_python = GetPythonImport(hDLL);
+
+ if (import_python &&
+ strcasecmp(buffer,import_python)) {
+ PyOS_snprintf(buffer, sizeof(buffer),
+ "Module use of %.150s conflicts "
+ "with this version of Python.",
+ import_python);
+ PyErr_SetString(PyExc_ImportError,buffer);
+ FreeLibrary(hDLL);
+ return NULL;
+ }
+ }
+ p = GetProcAddress(hDLL, funcname);
+ }
+
+ return p;
+}
diff --git a/contrib/tools/python/src/Python/errors.c b/contrib/tools/python/src/Python/errors.c
new file mode 100644
index 0000000000..d823e1397c
--- /dev/null
+++ b/contrib/tools/python/src/Python/errors.c
@@ -0,0 +1,830 @@
+
+/* Error handling */
+
+#include "Python.h"
+
+#ifndef __STDC__
+#ifndef MS_WINDOWS
+extern char *strerror(int);
+#endif
+#endif
+
+#ifdef MS_WINDOWS
+#include "windows.h"
+#include "winbase.h"
+#endif
+
+#include <ctype.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void
+PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *oldtype, *oldvalue, *oldtraceback;
+
+ if (traceback != NULL && !PyTraceBack_Check(traceback)) {
+ /* XXX Should never happen -- fatal error instead? */
+ /* Well, it could be None. */
+ Py_DECREF(traceback);
+ traceback = NULL;
+ }
+
+ /* Save these in locals to safeguard against recursive
+ invocation through Py_XDECREF */
+ oldtype = tstate->curexc_type;
+ oldvalue = tstate->curexc_value;
+ oldtraceback = tstate->curexc_traceback;
+
+ tstate->curexc_type = type;
+ tstate->curexc_value = value;
+ tstate->curexc_traceback = traceback;
+
+ Py_XDECREF(oldtype);
+ Py_XDECREF(oldvalue);
+ Py_XDECREF(oldtraceback);
+}
+
+void
+PyErr_SetObject(PyObject *exception, PyObject *value)
+{
+ Py_XINCREF(exception);
+ Py_XINCREF(value);
+ PyErr_Restore(exception, value, (PyObject *)NULL);
+}
+
+void
+PyErr_SetNone(PyObject *exception)
+{
+ PyErr_SetObject(exception, (PyObject *)NULL);
+}
+
+void
+PyErr_SetString(PyObject *exception, const char *string)
+{
+ PyObject *value = PyString_FromString(string);
+ PyErr_SetObject(exception, value);
+ Py_XDECREF(value);
+}
+
+
+PyObject *
+PyErr_Occurred(void)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ return tstate->curexc_type;
+}
+
+
+int
+PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
+{
+ if (err == NULL || exc == NULL) {
+ /* maybe caused by "import exceptions" that failed early on */
+ return 0;
+ }
+ if (PyTuple_Check(exc)) {
+ Py_ssize_t i, n;
+ n = PyTuple_Size(exc);
+ for (i = 0; i < n; i++) {
+ /* Test recursively */
+ if (PyErr_GivenExceptionMatches(
+ err, PyTuple_GET_ITEM(exc, i)))
+ {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ /* err might be an instance, so check its class. */
+ if (PyExceptionInstance_Check(err))
+ err = PyExceptionInstance_Class(err);
+
+ if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) {
+ int res = 0, reclimit;
+ PyObject *exception, *value, *tb;
+ PyErr_Fetch(&exception, &value, &tb);
+ /* Temporarily bump the recursion limit, so that in the most
+ common case PyObject_IsSubclass will not raise a recursion
+ error we have to ignore anyway. Don't do it when the limit
+ is already insanely high, to avoid overflow */
+ reclimit = Py_GetRecursionLimit();
+ if (reclimit < (1 << 30))
+ Py_SetRecursionLimit(reclimit + 5);
+ res = PyObject_IsSubclass(err, exc);
+ Py_SetRecursionLimit(reclimit);
+ /* This function must not fail, so print the error here */
+ if (res == -1) {
+ PyErr_WriteUnraisable(err);
+ res = 0;
+ }
+ PyErr_Restore(exception, value, tb);
+ return res;
+ }
+
+ return err == exc;
+}
+
+
+int
+PyErr_ExceptionMatches(PyObject *exc)
+{
+ return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc);
+}
+
+
+/* Used in many places to normalize a raised exception, including in
+ eval_code2(), do_raise(), and PyErr_Print()
+*/
+void
+PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
+{
+ PyObject *type = *exc;
+ PyObject *value = *val;
+ PyObject *inclass = NULL;
+ PyObject *initial_tb = NULL;
+ PyThreadState *tstate = NULL;
+
+ if (type == NULL) {
+ /* There was no exception, so nothing to do. */
+ return;
+ }
+
+ /* If PyErr_SetNone() was used, the value will have been actually
+ set to NULL.
+ */
+ if (!value) {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+
+ if (PyExceptionInstance_Check(value))
+ inclass = PyExceptionInstance_Class(value);
+
+ /* Normalize the exception so that if the type is a class, the
+ value will be an instance.
+ */
+ if (PyExceptionClass_Check(type)) {
+ /* if the value was not an instance, or is not an instance
+ whose class is (or is derived from) type, then use the
+ value as an argument to instantiation of the type
+ class.
+ */
+ if (!inclass || !PyObject_IsSubclass(inclass, type)) {
+ PyObject *args, *res;
+
+ if (value == Py_None)
+ args = PyTuple_New(0);
+ else if (PyTuple_Check(value)) {
+ Py_INCREF(value);
+ args = value;
+ }
+ else
+ args = PyTuple_Pack(1, value);
+
+ if (args == NULL)
+ goto finally;
+ res = PyEval_CallObject(type, args);
+ Py_DECREF(args);
+ if (res == NULL)
+ goto finally;
+ Py_DECREF(value);
+ value = res;
+ }
+ /* if the class of the instance doesn't exactly match the
+ class of the type, believe the instance
+ */
+ else if (inclass != type) {
+ Py_DECREF(type);
+ type = inclass;
+ Py_INCREF(type);
+ }
+ }
+ *exc = type;
+ *val = value;
+ return;
+finally:
+ Py_DECREF(type);
+ Py_DECREF(value);
+ /* If the new exception doesn't set a traceback and the old
+ exception had a traceback, use the old traceback for the
+ new exception. It's better than nothing.
+ */
+ initial_tb = *tb;
+ PyErr_Fetch(exc, val, tb);
+ if (initial_tb != NULL) {
+ if (*tb == NULL)
+ *tb = initial_tb;
+ else
+ Py_DECREF(initial_tb);
+ }
+ /* normalize recursively */
+ tstate = PyThreadState_GET();
+ if (++tstate->recursion_depth > Py_GetRecursionLimit()) {
+ --tstate->recursion_depth;
+ /* throw away the old exception and use the recursion error instead */
+ Py_INCREF(PyExc_RuntimeError);
+ Py_SETREF(*exc, PyExc_RuntimeError);
+ Py_INCREF(PyExc_RecursionErrorInst);
+ Py_SETREF(*val, PyExc_RecursionErrorInst);
+ /* just keeping the old traceback */
+ return;
+ }
+ PyErr_NormalizeException(exc, val, tb);
+ --tstate->recursion_depth;
+}
+
+
+void
+PyErr_Fetch(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ *p_type = tstate->curexc_type;
+ *p_value = tstate->curexc_value;
+ *p_traceback = tstate->curexc_traceback;
+
+ tstate->curexc_type = NULL;
+ tstate->curexc_value = NULL;
+ tstate->curexc_traceback = NULL;
+}
+
+void
+PyErr_Clear(void)
+{
+ PyErr_Restore(NULL, NULL, NULL);
+}
+
+/* Restore previously fetched exception if an exception is not set,
+ otherwise drop previously fetched exception.
+ Like _PyErr_ChainExceptions() in Python 3, but doesn't set the context.
+ */
+void
+_PyErr_ReplaceException(PyObject *exc, PyObject *val, PyObject *tb)
+{
+ if (exc == NULL)
+ return;
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(exc);
+ Py_XDECREF(val);
+ Py_XDECREF(tb);
+ }
+ else {
+ PyErr_Restore(exc, val, tb);
+ }
+}
+
+/* Convenience functions to set a type error exception and return 0 */
+
+int
+PyErr_BadArgument(void)
+{
+ PyErr_SetString(PyExc_TypeError,
+ "bad argument type for built-in operation");
+ return 0;
+}
+
+PyObject *
+PyErr_NoMemory(void)
+{
+ if (PyErr_ExceptionMatches(PyExc_MemoryError))
+ /* already current */
+ return NULL;
+
+ /* raise the pre-allocated instance if it still exists */
+ if (PyExc_MemoryErrorInst)
+ PyErr_SetObject(PyExc_MemoryError, PyExc_MemoryErrorInst);
+ else
+ /* this will probably fail since there's no memory and hee,
+ hee, we have to instantiate this class
+ */
+ PyErr_SetNone(PyExc_MemoryError);
+
+ return NULL;
+}
+
+PyObject *
+PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
+{
+ PyObject *v;
+ char *s;
+ int i = errno;
+#ifdef PLAN9
+ char errbuf[ERRMAX];
+#endif
+#ifdef MS_WINDOWS
+ char *s_buf = NULL;
+ char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
+#endif
+#ifdef EINTR
+ if (i == EINTR && PyErr_CheckSignals())
+ return NULL;
+#endif
+#ifdef PLAN9
+ rerrstr(errbuf, sizeof errbuf);
+ s = errbuf;
+#else
+ if (i == 0)
+ s = "Error"; /* Sometimes errno didn't get set */
+ else
+#ifndef MS_WINDOWS
+ s = strerror(i);
+#else
+ {
+ /* Note that the Win32 errors do not lineup with the
+ errno error. So if the error is in the MSVC error
+ table, we use it, otherwise we assume it really _is_
+ a Win32 error code
+ */
+ if (i > 0 && i < _sys_nerr) {
+ s = _sys_errlist[i];
+ }
+ else {
+ int len = FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, /* no message source */
+ i,
+ MAKELANGID(LANG_NEUTRAL,
+ SUBLANG_DEFAULT),
+ /* Default language */
+ (LPTSTR) &s_buf,
+ 0, /* size not used */
+ NULL); /* no args */
+ if (len==0) {
+ /* Only ever seen this in out-of-mem
+ situations */
+ sprintf(s_small_buf, "Windows Error 0x%X", i);
+ s = s_small_buf;
+ s_buf = NULL;
+ } else {
+ s = s_buf;
+ /* remove trailing cr/lf and dots */
+ while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
+ s[--len] = '\0';
+ }
+ }
+ }
+#endif /* Unix/Windows */
+#endif /* PLAN 9*/
+ if (filenameObject != NULL)
+ v = Py_BuildValue("(isO)", i, s, filenameObject);
+ else
+ v = Py_BuildValue("(is)", i, s);
+ if (v != NULL) {
+ PyErr_SetObject(exc, v);
+ Py_DECREF(v);
+ }
+#ifdef MS_WINDOWS
+ LocalFree(s_buf);
+#endif
+ return NULL;
+}
+
+
+PyObject *
+PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename)
+{
+ PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
+ Py_XDECREF(name);
+ return result;
+}
+
+#ifdef MS_WINDOWS
+PyObject *
+PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, const Py_UNICODE *filename)
+{
+ PyObject *name = filename ?
+ PyUnicode_FromUnicode(filename, wcslen(filename)) :
+ NULL;
+ PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
+ Py_XDECREF(name);
+ return result;
+}
+#endif /* MS_WINDOWS */
+
+PyObject *
+PyErr_SetFromErrno(PyObject *exc)
+{
+ return PyErr_SetFromErrnoWithFilenameObject(exc, NULL);
+}
+
+#ifdef MS_WINDOWS
+/* Windows specific error code handling */
+PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
+ PyObject *exc,
+ int ierr,
+ PyObject *filenameObject)
+{
+ int len;
+ char *s;
+ char *s_buf = NULL; /* Free via LocalFree */
+ char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
+ PyObject *v;
+ DWORD err = (DWORD)ierr;
+ if (err==0) err = GetLastError();
+ len = FormatMessage(
+ /* Error API error */
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, /* no message source */
+ err,
+ MAKELANGID(LANG_NEUTRAL,
+ SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &s_buf,
+ 0, /* size not used */
+ NULL); /* no args */
+ if (len==0) {
+ /* Only seen this in out of mem situations */
+ sprintf(s_small_buf, "Windows Error 0x%X", err);
+ s = s_small_buf;
+ s_buf = NULL;
+ } else {
+ s = s_buf;
+ /* remove trailing cr/lf and dots */
+ while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
+ s[--len] = '\0';
+ }
+ if (filenameObject != NULL)
+ v = Py_BuildValue("(isO)", err, s, filenameObject);
+ else
+ v = Py_BuildValue("(is)", err, s);
+ if (v != NULL) {
+ PyErr_SetObject(exc, v);
+ Py_DECREF(v);
+ }
+ LocalFree(s_buf);
+ return NULL;
+}
+
+PyObject *PyErr_SetExcFromWindowsErrWithFilename(
+ PyObject *exc,
+ int ierr,
+ const char *filename)
+{
+ PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
+ ierr,
+ name);
+ Py_XDECREF(name);
+ return ret;
+}
+
+PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilename(
+ PyObject *exc,
+ int ierr,
+ const Py_UNICODE *filename)
+{
+ PyObject *name = filename ?
+ PyUnicode_FromUnicode(filename, wcslen(filename)) :
+ NULL;
+ PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
+ ierr,
+ name);
+ Py_XDECREF(name);
+ return ret;
+}
+
+PyObject *PyErr_SetExcFromWindowsErr(PyObject *exc, int ierr)
+{
+ return PyErr_SetExcFromWindowsErrWithFilename(exc, ierr, NULL);
+}
+
+PyObject *PyErr_SetFromWindowsErr(int ierr)
+{
+ return PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
+ ierr, NULL);
+}
+PyObject *PyErr_SetFromWindowsErrWithFilename(
+ int ierr,
+ const char *filename)
+{
+ PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
+ PyExc_WindowsError,
+ ierr, name);
+ Py_XDECREF(name);
+ return result;
+}
+
+PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
+ int ierr,
+ const Py_UNICODE *filename)
+{
+ PyObject *name = filename ?
+ PyUnicode_FromUnicode(filename, wcslen(filename)) :
+ NULL;
+ PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
+ PyExc_WindowsError,
+ ierr, name);
+ Py_XDECREF(name);
+ return result;
+}
+#endif /* MS_WINDOWS */
+
+void
+_PyErr_BadInternalCall(const char *filename, int lineno)
+{
+ PyErr_Format(PyExc_SystemError,
+ "%s:%d: bad argument to internal function",
+ filename, lineno);
+}
+
+/* Remove the preprocessor macro for PyErr_BadInternalCall() so that we can
+ export the entry point for existing object code: */
+#undef PyErr_BadInternalCall
+void
+PyErr_BadInternalCall(void)
+{
+ PyErr_Format(PyExc_SystemError,
+ "bad argument to internal function");
+}
+#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__)
+
+
+
+PyObject *
+PyErr_Format(PyObject *exception, const char *format, ...)
+{
+ va_list vargs;
+ PyObject* string;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, format);
+#else
+ va_start(vargs);
+#endif
+
+ string = PyString_FromFormatV(format, vargs);
+ PyErr_SetObject(exception, string);
+ Py_XDECREF(string);
+ va_end(vargs);
+ return NULL;
+}
+
+
+
+PyObject *
+PyErr_NewException(char *name, PyObject *base, PyObject *dict)
+{
+ char *dot;
+ PyObject *modulename = NULL;
+ PyObject *classname = NULL;
+ PyObject *mydict = NULL;
+ PyObject *bases = NULL;
+ PyObject *result = NULL;
+ dot = strrchr(name, '.');
+ if (dot == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "PyErr_NewException: name must be module.class");
+ return NULL;
+ }
+ if (base == NULL)
+ base = PyExc_Exception;
+ if (dict == NULL) {
+ dict = mydict = PyDict_New();
+ if (dict == NULL)
+ goto failure;
+ }
+ if (PyDict_GetItemString(dict, "__module__") == NULL) {
+ modulename = PyString_FromStringAndSize(name,
+ (Py_ssize_t)(dot-name));
+ if (modulename == NULL)
+ goto failure;
+ if (PyDict_SetItemString(dict, "__module__", modulename) != 0)
+ goto failure;
+ }
+ if (PyTuple_Check(base)) {
+ bases = base;
+ /* INCREF as we create a new ref in the else branch */
+ Py_INCREF(bases);
+ } else {
+ bases = PyTuple_Pack(1, base);
+ if (bases == NULL)
+ goto failure;
+ }
+ /* Create a real new-style class. */
+ result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO",
+ dot+1, bases, dict);
+ failure:
+ Py_XDECREF(bases);
+ Py_XDECREF(mydict);
+ Py_XDECREF(classname);
+ Py_XDECREF(modulename);
+ return result;
+}
+
+
+/* Create an exception with docstring */
+PyObject *
+PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
+{
+ int result;
+ PyObject *ret = NULL;
+ PyObject *mydict = NULL; /* points to the dict only if we create it */
+ PyObject *docobj;
+
+ if (dict == NULL) {
+ dict = mydict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+ }
+
+ if (doc != NULL) {
+ docobj = PyString_FromString(doc);
+ if (docobj == NULL)
+ goto failure;
+ result = PyDict_SetItemString(dict, "__doc__", docobj);
+ Py_DECREF(docobj);
+ if (result < 0)
+ goto failure;
+ }
+
+ ret = PyErr_NewException(name, base, dict);
+ failure:
+ Py_XDECREF(mydict);
+ return ret;
+}
+
+
+/* Call when an exception has occurred but there is no way for Python
+ to handle it. Examples: exception in __del__ or during GC. */
+void
+PyErr_WriteUnraisable(PyObject *obj)
+{
+ PyObject *f, *t, *v, *tb;
+ PyErr_Fetch(&t, &v, &tb);
+ f = PySys_GetObject("stderr");
+ if (f != NULL) {
+ PyFile_WriteString("Exception ", f);
+ if (t) {
+ PyObject* moduleName;
+ char* className;
+ assert(PyExceptionClass_Check(t));
+ className = PyExceptionClass_Name(t);
+ if (className != NULL) {
+ char *dot = strrchr(className, '.');
+ if (dot != NULL)
+ className = dot+1;
+ }
+
+ moduleName = PyObject_GetAttrString(t, "__module__");
+ if (moduleName == NULL)
+ PyFile_WriteString("<unknown>", f);
+ else {
+ char* modstr = PyString_AsString(moduleName);
+ if (modstr &&
+ strcmp(modstr, "exceptions") != 0)
+ {
+ PyFile_WriteString(modstr, f);
+ PyFile_WriteString(".", f);
+ }
+ }
+ if (className == NULL)
+ PyFile_WriteString("<unknown>", f);
+ else
+ PyFile_WriteString(className, f);
+ if (v && v != Py_None) {
+ PyFile_WriteString(": ", f);
+ if (PyFile_WriteObject(v, f, 0) < 0) {
+ PyErr_Clear();
+ PyFile_WriteString("<exception repr() failed>", f);
+ }
+ }
+ Py_XDECREF(moduleName);
+ }
+ PyFile_WriteString(" in ", f);
+ if (PyFile_WriteObject(obj, f, 0) < 0) {
+ PyErr_Clear();
+ PyFile_WriteString("<object repr() failed>", f);
+ }
+ PyFile_WriteString(" ignored\n", f);
+ PyErr_Clear(); /* Just in case */
+ }
+ Py_XDECREF(t);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+}
+
+extern PyObject *PyModule_GetWarningsModule(void);
+
+
+/* Set file and line information for the current exception.
+ If the exception is not a SyntaxError, also sets additional attributes
+ to make printing of exceptions believe it is a syntax error. */
+
+void
+PyErr_SyntaxLocation(const char *filename, int lineno)
+{
+ PyObject *exc, *v, *tb, *tmp;
+
+ /* add attributes for the line number and filename for the error */
+ PyErr_Fetch(&exc, &v, &tb);
+ PyErr_NormalizeException(&exc, &v, &tb);
+ /* XXX check that it is, indeed, a syntax error. It might not
+ * be, though. */
+ tmp = PyInt_FromLong(lineno);
+ if (tmp == NULL)
+ PyErr_Clear();
+ else {
+ if (PyObject_SetAttrString(v, "lineno", tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ }
+ if (filename != NULL) {
+ tmp = PyString_FromString(filename);
+ if (tmp == NULL)
+ PyErr_Clear();
+ else {
+ if (PyObject_SetAttrString(v, "filename", tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ }
+
+ tmp = PyErr_ProgramText(filename, lineno);
+ if (tmp) {
+ if (PyObject_SetAttrString(v, "text", tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ }
+ }
+ if (PyObject_SetAttrString(v, "offset", Py_None)) {
+ PyErr_Clear();
+ }
+ if (exc != PyExc_SyntaxError) {
+ if (!PyObject_HasAttrString(v, "msg")) {
+ tmp = PyObject_Str(v);
+ if (tmp) {
+ if (PyObject_SetAttrString(v, "msg", tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ } else {
+ PyErr_Clear();
+ }
+ }
+ if (!PyObject_HasAttrString(v, "print_file_and_line")) {
+ if (PyObject_SetAttrString(v, "print_file_and_line",
+ Py_None))
+ PyErr_Clear();
+ }
+ }
+ PyErr_Restore(exc, v, tb);
+}
+
+/* com_fetch_program_text will attempt to load the line of text that
+ the exception refers to. If it fails, it will return NULL but will
+ not set an exception.
+
+ XXX The functionality of this function is quite similar to the
+ functionality in tb_displayline() in traceback.c.
+*/
+
+PyObject *
+PyErr_ProgramText(const char *filename, int lineno)
+{
+ FILE *fp;
+ int i;
+ char linebuf[1000];
+
+ if (filename == NULL || *filename == '\0' || lineno <= 0)
+ return NULL;
+ fp = fopen(filename, "r" PY_STDIOTEXTMODE);
+ if (fp == NULL)
+ return NULL;
+ for (i = 0; i < lineno; i++) {
+ char *pLastChar = &linebuf[sizeof(linebuf) - 2];
+ do {
+ *pLastChar = '\0';
+ if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, fp, NULL) == NULL)
+ break;
+ /* fgets read *something*; if it didn't get as
+ far as pLastChar, it must have found a newline
+ or hit the end of the file; if pLastChar is \n,
+ it obviously found a newline; else we haven't
+ yet seen a newline, so must continue */
+ } while (*pLastChar != '\0' && *pLastChar != '\n');
+ }
+ fclose(fp);
+ if (i == lineno) {
+ char *p = linebuf;
+ while (*p == ' ' || *p == '\t' || *p == '\014')
+ p++;
+ return PyString_FromString(p);
+ }
+ return NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/contrib/tools/python/src/Python/formatter_string.c b/contrib/tools/python/src/Python/formatter_string.c
new file mode 100644
index 0000000000..06a2ef5903
--- /dev/null
+++ b/contrib/tools/python/src/Python/formatter_string.c
@@ -0,0 +1,17 @@
+/***********************************************************************/
+/* Implements the string (as opposed to unicode) version of the
+ built-in formatters for string, int, float. That is, the versions
+ of int.__format__, etc., that take and return string objects */
+
+#include "Python.h"
+#include "../Objects/stringlib/stringdefs.h"
+
+#define FORMAT_STRING _PyBytes_FormatAdvanced
+#define FORMAT_LONG _PyLong_FormatAdvanced
+#define FORMAT_INT _PyInt_FormatAdvanced
+#define FORMAT_FLOAT _PyFloat_FormatAdvanced
+#ifndef WITHOUT_COMPLEX
+#define FORMAT_COMPLEX _PyComplex_FormatAdvanced
+#endif
+
+#include "../Objects/stringlib/formatter.h"
diff --git a/contrib/tools/python/src/Python/formatter_unicode.c b/contrib/tools/python/src/Python/formatter_unicode.c
new file mode 100644
index 0000000000..6e3685d16e
--- /dev/null
+++ b/contrib/tools/python/src/Python/formatter_unicode.c
@@ -0,0 +1,18 @@
+/* Implements the unicode (as opposed to string) version of the
+ built-in formatter for unicode. That is, unicode.__format__(). */
+
+#include "Python.h"
+
+#ifdef Py_USING_UNICODE
+
+#include "../Objects/stringlib/unicodedefs.h"
+
+#define FORMAT_STRING _PyUnicode_FormatAdvanced
+
+/* don't define FORMAT_LONG, FORMAT_FLOAT, and FORMAT_COMPLEX, since
+ we can live with only the string versions of those. The builtin
+ format() will convert them to unicode. */
+
+#include "../Objects/stringlib/formatter.h"
+
+#endif
diff --git a/contrib/tools/python/src/Python/frozen.c b/contrib/tools/python/src/Python/frozen.c
new file mode 100644
index 0000000000..ae7e9a4a93
--- /dev/null
+++ b/contrib/tools/python/src/Python/frozen.c
@@ -0,0 +1,38 @@
+
+/* Dummy frozen modules initializer */
+
+#include "Python.h"
+
+/* In order to test the support for frozen modules, by default we
+ define a single frozen module, __hello__. Loading it will print
+ some famous words... */
+
+/* To regenerate this data after the bytecode or marshal format has changed,
+ go to ../Tools/freeze/ and freeze the hello.py file; then copy and paste
+ the appropriate bytes from M___main__.c. */
+
+static unsigned char M___hello__[] = {
+ 99,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
+ 0,115,9,0,0,0,100,0,0,71,72,100,1,0,83,40,
+ 2,0,0,0,115,14,0,0,0,72,101,108,108,111,32,119,
+ 111,114,108,100,46,46,46,78,40,0,0,0,0,40,0,0,
+ 0,0,40,0,0,0,0,40,0,0,0,0,115,8,0,0,
+ 0,104,101,108,108,111,46,112,121,115,1,0,0,0,63,1,
+ 0,0,0,115,0,0,0,0,
+};
+
+#define SIZE (int)sizeof(M___hello__)
+
+static struct _frozen _PyImport_FrozenModules[] = {
+ /* Test module */
+ {"__hello__", M___hello__, SIZE},
+ /* Test package (negative size indicates package-ness) */
+ {"__phello__", M___hello__, -SIZE},
+ {"__phello__.spam", M___hello__, SIZE},
+ {0, 0, 0} /* sentinel */
+};
+
+/* Embedding apps may change this pointer to point to their favorite
+ collection of frozen modules: */
+
+struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules;
diff --git a/contrib/tools/python/src/Python/future.c b/contrib/tools/python/src/Python/future.c
new file mode 100644
index 0000000000..0e68845981
--- /dev/null
+++ b/contrib/tools/python/src/Python/future.c
@@ -0,0 +1,137 @@
+#include "Python.h"
+#include "Python-ast.h"
+#include "node.h"
+#include "token.h"
+#include "graminit.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+
+#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
+#define ERR_LATE_FUTURE \
+"from __future__ imports must occur at the beginning of the file"
+
+static int
+future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
+{
+ int i;
+ asdl_seq *names;
+
+ assert(s->kind == ImportFrom_kind);
+
+ names = s->v.ImportFrom.names;
+ for (i = 0; i < asdl_seq_LEN(names); i++) {
+ alias_ty name = (alias_ty)asdl_seq_GET(names, i);
+ const char *feature = PyString_AsString(name->name);
+ if (!feature)
+ return 0;
+ if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
+ continue;
+ } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
+ continue;
+ } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
+ ff->ff_features |= CO_FUTURE_DIVISION;
+ } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
+ ff->ff_features |= CO_FUTURE_ABSOLUTE_IMPORT;
+ } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
+ ff->ff_features |= CO_FUTURE_WITH_STATEMENT;
+ } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
+ ff->ff_features |= CO_FUTURE_PRINT_FUNCTION;
+ } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
+ ff->ff_features |= CO_FUTURE_UNICODE_LITERALS;
+ } else if (strcmp(feature, "braces") == 0) {
+ PyErr_SetString(PyExc_SyntaxError,
+ "not a chance");
+ PyErr_SyntaxLocation(filename, s->lineno);
+ return 0;
+ } else {
+ PyErr_Format(PyExc_SyntaxError,
+ UNDEFINED_FUTURE_FEATURE, feature);
+ PyErr_SyntaxLocation(filename, s->lineno);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
+{
+ int i, found_docstring = 0, done = 0, prev_line = 0;
+
+ if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
+ return 1;
+
+ /* A subsequent pass will detect future imports that don't
+ appear at the beginning of the file. There's one case,
+ however, that is easier to handle here: A series of imports
+ joined by semi-colons, where the first import is a future
+ statement but some subsequent import has the future form
+ but is preceded by a regular import.
+ */
+
+
+ for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
+ stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
+
+ if (done && s->lineno > prev_line)
+ return 1;
+ prev_line = s->lineno;
+
+ /* The tests below will return from this function unless it is
+ still possible to find a future statement. The only things
+ that can precede a future statement are another future
+ statement and a doc string.
+ */
+
+ if (s->kind == ImportFrom_kind) {
+ identifier modname = s->v.ImportFrom.module;
+ if (modname && PyString_GET_SIZE(modname) == 10 &&
+ !strcmp(PyString_AS_STRING(modname), "__future__")) {
+ if (done) {
+ PyErr_SetString(PyExc_SyntaxError,
+ ERR_LATE_FUTURE);
+ PyErr_SyntaxLocation(filename,
+ s->lineno);
+ return 0;
+ }
+ if (!future_check_features(ff, s, filename))
+ return 0;
+ ff->ff_lineno = s->lineno;
+ }
+ else
+ done = 1;
+ }
+ else if (s->kind == Expr_kind && !found_docstring) {
+ expr_ty e = s->v.Expr.value;
+ if (e->kind != Str_kind)
+ done = 1;
+ else
+ found_docstring = 1;
+ }
+ else
+ done = 1;
+ }
+ return 1;
+}
+
+
+PyFutureFeatures *
+PyFuture_FromAST(mod_ty mod, const char *filename)
+{
+ PyFutureFeatures *ff;
+
+ ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
+ if (ff == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ff->ff_features = 0;
+ ff->ff_lineno = -1;
+
+ if (!future_parse(ff, mod, filename)) {
+ PyObject_Free(ff);
+ return NULL;
+ }
+ return ff;
+}
diff --git a/contrib/tools/python/src/Python/getargs.c b/contrib/tools/python/src/Python/getargs.c
new file mode 100644
index 0000000000..cc1ddde977
--- /dev/null
+++ b/contrib/tools/python/src/Python/getargs.c
@@ -0,0 +1,1934 @@
+
+/* New getargs implementation */
+
+#include "Python.h"
+
+#include <ctype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int PyArg_Parse(PyObject *, const char *, ...);
+int PyArg_ParseTuple(PyObject *, const char *, ...);
+int PyArg_VaParse(PyObject *, const char *, va_list);
+
+int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
+ const char *, char **, ...);
+int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
+ const char *, char **, va_list);
+
+#ifdef HAVE_DECLSPEC_DLL
+/* Export functions */
+PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
+ const char *, char **, ...);
+PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
+PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, char *, va_list);
+PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
+ const char *, char **, va_list);
+#endif
+
+#define FLAG_COMPAT 1
+#define FLAG_SIZE_T 2
+
+
+/* Forward */
+static int vgetargs1(PyObject *, const char *, va_list *, int);
+static void seterror(int, const char *, int *, const char *, const char *);
+static char *convertitem(PyObject *, const char **, va_list *, int, int *,
+ char *, size_t, PyObject **);
+static char *converttuple(PyObject *, const char **, va_list *, int,
+ int *, char *, size_t, int, PyObject **);
+static char *convertsimple(PyObject *, const char **, va_list *, int, char *,
+ size_t, PyObject **);
+static Py_ssize_t convertbuffer(PyObject *, void **p, char **);
+static int getbuffer(PyObject *, Py_buffer *, char**);
+
+static int vgetargskeywords(PyObject *, PyObject *,
+ const char *, char **, va_list *, int);
+static char *skipitem(const char **, va_list *, int);
+
+int
+PyArg_Parse(PyObject *args, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_COMPAT);
+ va_end(va);
+ return retval;
+}
+
+int
+_PyArg_Parse_SizeT(PyObject *args, char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_COMPAT|FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+PyArg_ParseTuple(PyObject *args, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+int
+_PyArg_ParseTuple_SizeT(PyObject *args, char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+PyArg_VaParse(PyObject *args, const char *format, va_list va)
+{
+ va_list lva;
+
+#ifdef VA_LIST_IS_ARRAY
+ memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(lva, va);
+#else
+ lva = va;
+#endif
+#endif
+
+ return vgetargs1(args, format, &lva, 0);
+}
+
+int
+_PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
+{
+ va_list lva;
+
+#ifdef VA_LIST_IS_ARRAY
+ memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(lva, va);
+#else
+ lva = va;
+#endif
+#endif
+
+ return vgetargs1(args, format, &lva, FLAG_SIZE_T);
+}
+
+
+/* Handle cleanup of allocated memory in case of exception */
+
+#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr"
+#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer"
+
+static void
+cleanup_ptr(PyObject *self)
+{
+ void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR);
+ if (ptr) {
+ PyMem_FREE(ptr);
+ }
+}
+
+static void
+cleanup_buffer(PyObject *self)
+{
+ Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER);
+ if (ptr) {
+ PyBuffer_Release(ptr);
+ }
+}
+
+static int
+addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr)
+{
+ PyObject *cobj;
+ const char *name;
+
+ if (!*freelist) {
+ *freelist = PyList_New(0);
+ if (!*freelist) {
+ destr(ptr);
+ return -1;
+ }
+ }
+
+ if (destr == cleanup_ptr) {
+ name = GETARGS_CAPSULE_NAME_CLEANUP_PTR;
+ } else if (destr == cleanup_buffer) {
+ name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER;
+ } else {
+ return -1;
+ }
+ cobj = PyCapsule_New(ptr, name, destr);
+ if (!cobj) {
+ destr(ptr);
+ return -1;
+ }
+ if (PyList_Append(*freelist, cobj)) {
+ Py_DECREF(cobj);
+ return -1;
+ }
+ Py_DECREF(cobj);
+ return 0;
+}
+
+static int
+cleanreturn(int retval, PyObject *freelist)
+{
+ if (freelist && retval != 0) {
+ /* We were successful, reset the destructors so that they
+ don't get called. */
+ Py_ssize_t len = PyList_GET_SIZE(freelist), i;
+ for (i = 0; i < len; i++)
+ PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL);
+ }
+ Py_XDECREF(freelist);
+ return retval;
+}
+
+
+static int
+vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
+{
+ char msgbuf[256];
+ int levels[32];
+ const char *fname = NULL;
+ const char *message = NULL;
+ int min = -1;
+ int max = 0;
+ int level = 0;
+ int endfmt = 0;
+ const char *formatsave = format;
+ Py_ssize_t i, len;
+ char *msg;
+ PyObject *freelist = NULL;
+ int compat = flags & FLAG_COMPAT;
+
+ assert(compat || (args != (PyObject*)NULL));
+ flags = flags & ~FLAG_COMPAT;
+
+ while (endfmt == 0) {
+ int c = *format++;
+ switch (c) {
+ case '(':
+ if (level == 0)
+ max++;
+ level++;
+ if (level >= 30)
+ Py_FatalError("too many tuple nesting levels "
+ "in argument format string");
+ break;
+ case ')':
+ if (level == 0)
+ Py_FatalError("excess ')' in getargs format");
+ else
+ level--;
+ break;
+ case '\0':
+ endfmt = 1;
+ break;
+ case ':':
+ fname = format;
+ endfmt = 1;
+ break;
+ case ';':
+ message = format;
+ endfmt = 1;
+ break;
+ default:
+ if (level == 0) {
+ if (c == 'O')
+ max++;
+ else if (isalpha(Py_CHARMASK(c))) {
+ if (c != 'e') /* skip encoded */
+ max++;
+ } else if (c == '|')
+ min = max;
+ }
+ break;
+ }
+ }
+
+ if (level != 0)
+ Py_FatalError(/* '(' */ "missing ')' in getargs format");
+
+ if (min < 0)
+ min = max;
+
+ format = formatsave;
+
+ if (compat) {
+ if (max == 0) {
+ if (args == NULL)
+ return 1;
+ PyOS_snprintf(msgbuf, sizeof(msgbuf),
+ "%.200s%s takes no arguments",
+ fname==NULL ? "function" : fname,
+ fname==NULL ? "" : "()");
+ PyErr_SetString(PyExc_TypeError, msgbuf);
+ return 0;
+ }
+ else if (min == 1 && max == 1) {
+ if (args == NULL) {
+ PyOS_snprintf(msgbuf, sizeof(msgbuf),
+ "%.200s%s takes at least one argument",
+ fname==NULL ? "function" : fname,
+ fname==NULL ? "" : "()");
+ PyErr_SetString(PyExc_TypeError, msgbuf);
+ return 0;
+ }
+ msg = convertitem(args, &format, p_va, flags, levels,
+ msgbuf, sizeof(msgbuf), &freelist);
+ if (msg == NULL)
+ return cleanreturn(1, freelist);
+ seterror(levels[0], msg, levels+1, fname, message);
+ return cleanreturn(0, freelist);
+ }
+ else {
+ PyErr_SetString(PyExc_SystemError,
+ "old style getargs format uses new features");
+ return 0;
+ }
+ }
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_SystemError,
+ "new style getargs format but argument is not a tuple");
+ return 0;
+ }
+
+ len = PyTuple_GET_SIZE(args);
+
+ if (len < min || max < len) {
+ if (message == NULL) {
+ PyOS_snprintf(msgbuf, sizeof(msgbuf),
+ "%.150s%s takes %s %d argument%s "
+ "(%ld given)",
+ fname==NULL ? "function" : fname,
+ fname==NULL ? "" : "()",
+ min==max ? "exactly"
+ : len < min ? "at least" : "at most",
+ len < min ? min : max,
+ (len < min ? min : max) == 1 ? "" : "s",
+ Py_SAFE_DOWNCAST(len, Py_ssize_t, long));
+ message = msgbuf;
+ }
+ PyErr_SetString(PyExc_TypeError, message);
+ return 0;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (*format == '|')
+ format++;
+ msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
+ flags, levels, msgbuf,
+ sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, fname, message);
+ return cleanreturn(0, freelist);
+ }
+ }
+
+ if (*format != '\0' && !isalpha(Py_CHARMASK(*format)) &&
+ *format != '(' &&
+ *format != '|' && *format != ':' && *format != ';') {
+ PyErr_Format(PyExc_SystemError,
+ "bad format string: %.200s", formatsave);
+ return cleanreturn(0, freelist);
+ }
+
+ return cleanreturn(1, freelist);
+}
+
+
+
+static void
+seterror(int iarg, const char *msg, int *levels, const char *fname,
+ const char *message)
+{
+ char buf[512];
+ int i;
+ char *p = buf;
+
+ if (PyErr_Occurred())
+ return;
+ else if (message == NULL) {
+ if (fname != NULL) {
+ PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname);
+ p += strlen(p);
+ }
+ if (iarg != 0) {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf),
+ "argument %d", iarg);
+ i = 0;
+ p += strlen(p);
+ while (levels[i] > 0 && i < 32 && (int)(p-buf) < 220) {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf),
+ ", item %d", levels[i]-1);
+ p += strlen(p);
+ i++;
+ }
+ }
+ else {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument");
+ p += strlen(p);
+ }
+ PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);
+ message = buf;
+ }
+ PyErr_SetString(PyExc_TypeError, message);
+}
+
+
+/* Convert a tuple argument.
+ On entry, *p_format points to the character _after_ the opening '('.
+ On successful exit, *p_format points to the closing ')'.
+ If successful:
+ *p_format and *p_va are updated,
+ *levels and *msgbuf are untouched,
+ and NULL is returned.
+ If the argument is invalid:
+ *p_format is unchanged,
+ *p_va is undefined,
+ *levels is a 0-terminated list of item numbers,
+ *msgbuf contains an error message, whose format is:
+ "must be <typename1>, not <typename2>", where:
+ <typename1> is the name of the expected type, and
+ <typename2> is the name of the actual type,
+ and msgbuf is returned.
+*/
+
+static char *
+converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
+ int *levels, char *msgbuf, size_t bufsize, int toplevel,
+ PyObject **freelist)
+{
+ int level = 0;
+ int n = 0;
+ const char *format = *p_format;
+ int i;
+
+ for (;;) {
+ int c = *format++;
+ if (c == '(') {
+ if (level == 0)
+ n++;
+ level++;
+ }
+ else if (c == ')') {
+ if (level == 0)
+ break;
+ level--;
+ }
+ else if (c == ':' || c == ';' || c == '\0')
+ break;
+ else if (level == 0 && isalpha(Py_CHARMASK(c)))
+ n++;
+ }
+
+ if (!PySequence_Check(arg) || PyString_Check(arg)) {
+ levels[0] = 0;
+ PyOS_snprintf(msgbuf, bufsize,
+ toplevel ? "expected %d arguments, not %.50s" :
+ "must be %d-item sequence, not %.50s",
+ n,
+ arg == Py_None ? "None" : arg->ob_type->tp_name);
+ return msgbuf;
+ }
+
+ if ((i = PySequence_Size(arg)) != n) {
+ levels[0] = 0;
+ PyOS_snprintf(msgbuf, bufsize,
+ toplevel ? "expected %d arguments, not %d" :
+ "must be sequence of length %d, not %d",
+ n, i);
+ return msgbuf;
+ }
+
+ format = *p_format;
+ for (i = 0; i < n; i++) {
+ char *msg;
+ PyObject *item;
+ item = PySequence_GetItem(arg, i);
+ if (item == NULL) {
+ PyErr_Clear();
+ levels[0] = i+1;
+ levels[1] = 0;
+ strncpy(msgbuf, "is not retrievable", bufsize);
+ return msgbuf;
+ }
+ msg = convertitem(item, &format, p_va, flags, levels+1,
+ msgbuf, bufsize, freelist);
+ /* PySequence_GetItem calls tp->sq_item, which INCREFs */
+ Py_XDECREF(item);
+ if (msg != NULL) {
+ levels[0] = i+1;
+ return msg;
+ }
+ }
+
+ *p_format = format;
+ return NULL;
+}
+
+
+/* Convert a single item. */
+
+static char *
+convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
+ int *levels, char *msgbuf, size_t bufsize, PyObject **freelist)
+{
+ char *msg;
+ const char *format = *p_format;
+
+ if (*format == '(' /* ')' */) {
+ format++;
+ msg = converttuple(arg, &format, p_va, flags, levels, msgbuf,
+ bufsize, 0, freelist);
+ if (msg == NULL)
+ format++;
+ }
+ else {
+ msg = convertsimple(arg, &format, p_va, flags,
+ msgbuf, bufsize, freelist);
+ if (msg != NULL)
+ levels[0] = 0;
+ }
+ if (msg == NULL)
+ *p_format = format;
+ return msg;
+}
+
+
+
+#define UNICODE_DEFAULT_ENCODING(arg) \
+ _PyUnicode_AsDefaultEncodedString(arg, NULL)
+
+/* Format an error message generated by convertsimple(). */
+
+static char *
+converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
+{
+ assert(expected != NULL);
+ assert(arg != NULL);
+ if (expected[0] == '(') {
+ PyOS_snprintf(msgbuf, bufsize,
+ "%.100s", expected);
+ strncpy(msgbuf, expected, bufsize);
+ msgbuf[bufsize-1] = '\0';
+ }
+ else {
+ PyOS_snprintf(msgbuf, bufsize,
+ "must be %.50s, not %.50s", expected,
+ arg == Py_None ? "None" : arg->ob_type->tp_name);
+ }
+ return msgbuf;
+}
+
+#define CONV_UNICODE "(unicode conversion error)"
+
+/* explicitly check for float arguments when integers are expected. For now
+ * signal a warning. Returns true if an exception was raised. */
+static int
+float_argument_warning(PyObject *arg)
+{
+ if (PyFloat_Check(arg) &&
+ PyErr_Warn(PyExc_DeprecationWarning,
+ "integer argument expected, got float" ))
+ return 1;
+ else
+ return 0;
+}
+
+/* explicitly check for float arguments when integers are expected. Raises
+ TypeError and returns true for float arguments. */
+static int
+float_argument_error(PyObject *arg)
+{
+ if (PyFloat_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "integer argument expected, got float");
+ return 1;
+ }
+ else
+ return 0;
+}
+
+#ifdef Py_USING_UNICODE
+static size_t
+_ustrlen(Py_UNICODE *u)
+{
+ size_t i = 0;
+ Py_UNICODE *v = u;
+ while (*v != 0) { i++; v++; }
+ return i;
+}
+#endif
+
+/* Convert a non-tuple argument. Return NULL if conversion went OK,
+ or a string with a message describing the failure. The message is
+ formatted as "must be <desired type>, not <actual type>".
+ When failing, an exception may or may not have been raised.
+ Don't call if a tuple is expected.
+
+ When you add new format codes, please don't forget poor skipitem() below.
+*/
+
+static char *
+convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
+ char *msgbuf, size_t bufsize, PyObject **freelist)
+{
+ /* For # codes */
+#define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\
+ if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \
+ else q=va_arg(*p_va, int*);
+#define STORE_SIZE(s) \
+ if (flags & FLAG_SIZE_T) \
+ *q2=s; \
+ else { \
+ if (INT_MAX < s) { \
+ PyErr_SetString(PyExc_OverflowError, \
+ "size does not fit in an int"); \
+ return converterr("", arg, msgbuf, bufsize); \
+ } \
+ *q=s; \
+ }
+#define BUFFER_LEN ((flags & FLAG_SIZE_T) ? *q2:*q)
+
+ const char *format = *p_format;
+ char c = *format++;
+#ifdef Py_USING_UNICODE
+ PyObject *uarg;
+#endif
+
+ switch (c) {
+
+ case 'b': { /* unsigned byte -- very short int */
+ char *p = va_arg(*p_va, char *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<b>", arg, msgbuf, bufsize);
+ ival = PyInt_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<b>", arg, msgbuf, bufsize);
+ else if (ival < 0) {
+ PyErr_SetString(PyExc_OverflowError,
+ "unsigned byte integer is less than minimum");
+ return converterr("integer<b>", arg, msgbuf, bufsize);
+ }
+ else if (ival > UCHAR_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "unsigned byte integer is greater than maximum");
+ return converterr("integer<b>", arg, msgbuf, bufsize);
+ }
+ else
+ *p = (unsigned char) ival;
+ break;
+ }
+
+ case 'B': {/* byte sized bitfield - both signed and unsigned
+ values allowed */
+ char *p = va_arg(*p_va, char *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<B>", arg, msgbuf, bufsize);
+ ival = PyInt_AsUnsignedLongMask(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<B>", arg, msgbuf, bufsize);
+ else
+ *p = (unsigned char) ival;
+ break;
+ }
+
+ case 'h': {/* signed short int */
+ short *p = va_arg(*p_va, short *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<h>", arg, msgbuf, bufsize);
+ ival = PyInt_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<h>", arg, msgbuf, bufsize);
+ else if (ival < SHRT_MIN) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed short integer is less than minimum");
+ return converterr("integer<h>", arg, msgbuf, bufsize);
+ }
+ else if (ival > SHRT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed short integer is greater than maximum");
+ return converterr("integer<h>", arg, msgbuf, bufsize);
+ }
+ else
+ *p = (short) ival;
+ break;
+ }
+
+ case 'H': { /* short int sized bitfield, both signed and
+ unsigned allowed */
+ unsigned short *p = va_arg(*p_va, unsigned short *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<H>", arg, msgbuf, bufsize);
+ ival = PyInt_AsUnsignedLongMask(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<H>", arg, msgbuf, bufsize);
+ else
+ *p = (unsigned short) ival;
+ break;
+ }
+
+ case 'i': {/* signed int */
+ int *p = va_arg(*p_va, int *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<i>", arg, msgbuf, bufsize);
+ ival = PyInt_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<i>", arg, msgbuf, bufsize);
+ else if (ival > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed integer is greater than maximum");
+ return converterr("integer<i>", arg, msgbuf, bufsize);
+ }
+ else if (ival < INT_MIN) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed integer is less than minimum");
+ return converterr("integer<i>", arg, msgbuf, bufsize);
+ }
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'I': { /* int sized bitfield, both signed and
+ unsigned allowed */
+ unsigned int *p = va_arg(*p_va, unsigned int *);
+ unsigned int ival;
+ if (float_argument_error(arg))
+ return converterr("integer<I>", arg, msgbuf, bufsize);
+ ival = (unsigned int)PyInt_AsUnsignedLongMask(arg);
+ if (ival == (unsigned int)-1 && PyErr_Occurred())
+ return converterr("integer<I>", arg, msgbuf, bufsize);
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'n': /* Py_ssize_t */
+#if SIZEOF_SIZE_T != SIZEOF_LONG
+ {
+ Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *);
+ Py_ssize_t ival;
+ if (float_argument_error(arg))
+ return converterr("integer<n>", arg, msgbuf, bufsize);
+ ival = PyInt_AsSsize_t(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<n>", arg, msgbuf, bufsize);
+ *p = ival;
+ break;
+ }
+#endif
+ /* Fall through from 'n' to 'l' if Py_ssize_t is int */
+ case 'l': {/* long int */
+ long *p = va_arg(*p_va, long *);
+ long ival;
+ if (float_argument_error(arg))
+ return converterr("integer<l>", arg, msgbuf, bufsize);
+ ival = PyInt_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ return converterr("integer<l>", arg, msgbuf, bufsize);
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'k': { /* long sized bitfield */
+ unsigned long *p = va_arg(*p_va, unsigned long *);
+ unsigned long ival;
+ if (PyInt_Check(arg))
+ ival = PyInt_AsUnsignedLongMask(arg);
+ else if (PyLong_Check(arg))
+ ival = PyLong_AsUnsignedLongMask(arg);
+ else
+ return converterr("an integer", arg, msgbuf, bufsize);
+ *p = ival;
+ break;
+ }
+
+#ifdef HAVE_LONG_LONG
+ case 'L': {/* PY_LONG_LONG */
+ PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * );
+ PY_LONG_LONG ival;
+ if (float_argument_warning(arg))
+ return converterr("long<L>", arg, msgbuf, bufsize);
+ ival = PyLong_AsLongLong(arg);
+ if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) {
+ return converterr("long<L>", arg, msgbuf, bufsize);
+ } else {
+ *p = ival;
+ }
+ break;
+ }
+
+ case 'K': { /* long long sized bitfield */
+ unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *);
+ unsigned PY_LONG_LONG ival;
+ if (PyInt_Check(arg))
+ ival = PyInt_AsUnsignedLongMask(arg);
+ else if (PyLong_Check(arg))
+ ival = PyLong_AsUnsignedLongLongMask(arg);
+ else
+ return converterr("an integer", arg, msgbuf, bufsize);
+ *p = ival;
+ break;
+ }
+#endif
+
+ case 'f': {/* float */
+ float *p = va_arg(*p_va, float *);
+ double dval = PyFloat_AsDouble(arg);
+ if (PyErr_Occurred())
+ return converterr("float<f>", arg, msgbuf, bufsize);
+ else
+ *p = (float) dval;
+ break;
+ }
+
+ case 'd': {/* double */
+ double *p = va_arg(*p_va, double *);
+ double dval = PyFloat_AsDouble(arg);
+ if (PyErr_Occurred())
+ return converterr("float<d>", arg, msgbuf, bufsize);
+ else
+ *p = dval;
+ break;
+ }
+
+#ifndef WITHOUT_COMPLEX
+ case 'D': {/* complex double */
+ Py_complex *p = va_arg(*p_va, Py_complex *);
+ Py_complex cval;
+ cval = PyComplex_AsCComplex(arg);
+ if (PyErr_Occurred())
+ return converterr("complex<D>", arg, msgbuf, bufsize);
+ else
+ *p = cval;
+ break;
+ }
+#endif /* WITHOUT_COMPLEX */
+
+ case 'c': {/* char */
+ char *p = va_arg(*p_va, char *);
+ if (PyString_Check(arg) && PyString_Size(arg) == 1)
+ *p = PyString_AS_STRING(arg)[0];
+ else
+ return converterr("char", arg, msgbuf, bufsize);
+ break;
+ }
+
+ case 's': {/* string */
+ if (*format == '*') {
+ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
+
+ if (PyString_Check(arg)) {
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
+ 1, 0);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
+ 1, 0);
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ if (getbuffer(arg, p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ }
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ format++;
+ } else if (*format == '#') {
+ void **p = (void **)va_arg(*p_va, char **);
+ FETCH_SIZE;
+
+ if (PyString_Check(arg)) {
+ *p = PyString_AS_STRING(arg);
+ STORE_SIZE(PyString_GET_SIZE(arg));
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ *p = PyString_AS_STRING(uarg);
+ STORE_SIZE(PyString_GET_SIZE(uarg));
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ Py_ssize_t count = convertbuffer(arg, p, &buf);
+ if (count < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ STORE_SIZE(count);
+ }
+ format++;
+ } else {
+ char **p = va_arg(*p_va, char **);
+
+ if (PyString_Check(arg))
+ *p = PyString_AS_STRING(arg);
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ *p = PyString_AS_STRING(uarg);
+ }
+#endif
+ else
+ return converterr("string", arg, msgbuf, bufsize);
+ if ((Py_ssize_t)strlen(*p) != PyString_Size(arg))
+ return converterr("string without null bytes",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+
+ case 'z': {/* string, may be NULL (None) */
+ if (*format == '*') {
+ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
+
+ if (arg == Py_None)
+ PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0);
+ else if (PyString_Check(arg)) {
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
+ 1, 0);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
+ 1, 0);
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ if (getbuffer(arg, p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ }
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ format++;
+ } else if (*format == '#') { /* any buffer-like object */
+ void **p = (void **)va_arg(*p_va, char **);
+ FETCH_SIZE;
+
+ if (arg == Py_None) {
+ *p = 0;
+ STORE_SIZE(0);
+ }
+ else if (PyString_Check(arg)) {
+ *p = PyString_AS_STRING(arg);
+ STORE_SIZE(PyString_GET_SIZE(arg));
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ *p = PyString_AS_STRING(uarg);
+ STORE_SIZE(PyString_GET_SIZE(uarg));
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ Py_ssize_t count = convertbuffer(arg, p, &buf);
+ if (count < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ STORE_SIZE(count);
+ }
+ format++;
+ } else {
+ char **p = va_arg(*p_va, char **);
+
+ if (arg == Py_None)
+ *p = 0;
+ else if (PyString_Check(arg))
+ *p = PyString_AS_STRING(arg);
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ *p = PyString_AS_STRING(uarg);
+ }
+#endif
+ else
+ return converterr("string or None",
+ arg, msgbuf, bufsize);
+ if (*format == '#') {
+ FETCH_SIZE;
+ assert(0); /* XXX redundant with if-case */
+ if (arg == Py_None) {
+ STORE_SIZE(0);
+ } else {
+ STORE_SIZE(PyString_Size(arg));
+ }
+ format++;
+ }
+ else if (*p != NULL &&
+ (Py_ssize_t)strlen(*p) != PyString_Size(arg))
+ return converterr(
+ "string without null bytes or None",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+
+ case 'e': {/* encoded string */
+ char **buffer;
+ const char *encoding;
+ PyObject *s;
+ Py_ssize_t size;
+ int recode_strings;
+
+ /* Get 'e' parameter: the encoding name */
+ encoding = (const char *)va_arg(*p_va, const char *);
+#ifdef Py_USING_UNICODE
+ if (encoding == NULL)
+ encoding = PyUnicode_GetDefaultEncoding();
+#endif
+
+ /* Get output buffer parameter:
+ 's' (recode all objects via Unicode) or
+ 't' (only recode non-string objects)
+ */
+ if (*format == 's')
+ recode_strings = 1;
+ else if (*format == 't')
+ recode_strings = 0;
+ else
+ return converterr(
+ "(unknown parser marker combination)",
+ arg, msgbuf, bufsize);
+ buffer = (char **)va_arg(*p_va, char **);
+ format++;
+ if (buffer == NULL)
+ return converterr("(buffer is NULL)",
+ arg, msgbuf, bufsize);
+
+ /* Encode object */
+ if (!recode_strings && PyString_Check(arg)) {
+ s = arg;
+ Py_INCREF(s);
+ }
+ else {
+#ifdef Py_USING_UNICODE
+ PyObject *u;
+
+ /* Convert object to Unicode */
+ u = PyUnicode_FromObject(arg);
+ if (u == NULL)
+ return converterr(
+ "string or unicode or text buffer",
+ arg, msgbuf, bufsize);
+
+ /* Encode object; use default error handling */
+ s = PyUnicode_AsEncodedString(u,
+ encoding,
+ NULL);
+ Py_DECREF(u);
+ if (s == NULL)
+ return converterr("(encoding failed)",
+ arg, msgbuf, bufsize);
+ if (!PyString_Check(s)) {
+ Py_DECREF(s);
+ return converterr(
+ "(encoder failed to return a string)",
+ arg, msgbuf, bufsize);
+ }
+#else
+ return converterr("string<e>", arg, msgbuf, bufsize);
+#endif
+ }
+ size = PyString_GET_SIZE(s);
+
+ /* Write output; output is guaranteed to be 0-terminated */
+ if (*format == '#') {
+ /* Using buffer length parameter '#':
+
+ - if *buffer is NULL, a new buffer of the
+ needed size is allocated and the data
+ copied into it; *buffer is updated to point
+ to the new buffer; the caller is
+ responsible for PyMem_Free()ing it after
+ usage
+
+ - if *buffer is not NULL, the data is
+ copied to *buffer; *buffer_len has to be
+ set to the size of the buffer on input;
+ buffer overflow is signalled with an error;
+ buffer has to provide enough room for the
+ encoded string plus the trailing 0-byte
+
+ - in both cases, *buffer_len is updated to
+ the size of the buffer /excluding/ the
+ trailing 0-byte
+
+ */
+ FETCH_SIZE;
+
+ format++;
+ if (q == NULL && q2 == NULL) {
+ Py_DECREF(s);
+ return converterr(
+ "(buffer_len is NULL)",
+ arg, msgbuf, bufsize);
+ }
+ if (*buffer == NULL) {
+ *buffer = PyMem_NEW(char, size + 1);
+ if (*buffer == NULL) {
+ Py_DECREF(s);
+ return converterr(
+ "(memory error)",
+ arg, msgbuf, bufsize);
+ }
+ if (addcleanup(*buffer, freelist, cleanup_ptr)) {
+ Py_DECREF(s);
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ } else {
+ if (size + 1 > BUFFER_LEN) {
+ Py_DECREF(s);
+ PyErr_Format(PyExc_TypeError,
+ "encoded string too long "
+ "(%zd, maximum length %zd)",
+ (Py_ssize_t)size, (Py_ssize_t)(BUFFER_LEN-1));
+ return "";
+ }
+ }
+ memcpy(*buffer,
+ PyString_AS_STRING(s),
+ size + 1);
+ STORE_SIZE(size);
+ } else {
+ /* Using a 0-terminated buffer:
+
+ - the encoded string has to be 0-terminated
+ for this variant to work; if it is not, an
+ error raised
+
+ - a new buffer of the needed size is
+ allocated and the data copied into it;
+ *buffer is updated to point to the new
+ buffer; the caller is responsible for
+ PyMem_Free()ing it after usage
+
+ */
+ if ((Py_ssize_t)strlen(PyString_AS_STRING(s))
+ != size) {
+ Py_DECREF(s);
+ return converterr(
+ "encoded string without null bytes",
+ arg, msgbuf, bufsize);
+ }
+ *buffer = PyMem_NEW(char, size + 1);
+ if (*buffer == NULL) {
+ Py_DECREF(s);
+ return converterr("(memory error)",
+ arg, msgbuf, bufsize);
+ }
+ if (addcleanup(*buffer, freelist, cleanup_ptr)) {
+ Py_DECREF(s);
+ return converterr("(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ memcpy(*buffer,
+ PyString_AS_STRING(s),
+ size + 1);
+ }
+ Py_DECREF(s);
+ break;
+ }
+
+#ifdef Py_USING_UNICODE
+ case 'u': {/* raw unicode buffer (Py_UNICODE *) */
+ if (*format == '#') { /* any buffer-like object */
+ void **p = (void **)va_arg(*p_va, char **);
+ FETCH_SIZE;
+ if (PyUnicode_Check(arg)) {
+ *p = PyUnicode_AS_UNICODE(arg);
+ STORE_SIZE(PyUnicode_GET_SIZE(arg));
+ }
+ else {
+ return converterr("cannot convert raw buffers",
+ arg, msgbuf, bufsize);
+ }
+ format++;
+ } else {
+ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
+ if (PyUnicode_Check(arg)) {
+ *p = PyUnicode_AS_UNICODE(arg);
+ if (_ustrlen(*p) != (size_t)PyUnicode_GET_SIZE(arg)) {
+ return converterr(
+ "unicode without null characters",
+ arg, msgbuf, bufsize);
+ }
+ }
+ else
+ return converterr("unicode", arg, msgbuf, bufsize);
+ }
+ break;
+ }
+#endif
+
+ case 'S': { /* string object */
+ PyObject **p = va_arg(*p_va, PyObject **);
+ if (PyString_Check(arg))
+ *p = arg;
+ else
+ return converterr("string", arg, msgbuf, bufsize);
+ break;
+ }
+
+#ifdef Py_USING_UNICODE
+ case 'U': { /* Unicode object */
+ PyObject **p = va_arg(*p_va, PyObject **);
+ if (PyUnicode_Check(arg))
+ *p = arg;
+ else
+ return converterr("unicode", arg, msgbuf, bufsize);
+ break;
+ }
+#endif
+
+ case 'O': { /* object */
+ PyTypeObject *type;
+ PyObject **p;
+ if (*format == '!') {
+ type = va_arg(*p_va, PyTypeObject*);
+ p = va_arg(*p_va, PyObject **);
+ format++;
+ if (PyType_IsSubtype(arg->ob_type, type))
+ *p = arg;
+ else
+ return converterr(type->tp_name, arg, msgbuf, bufsize);
+
+ }
+ else if (*format == '?') {
+ inquiry pred = va_arg(*p_va, inquiry);
+ p = va_arg(*p_va, PyObject **);
+ format++;
+ if ((*pred)(arg))
+ *p = arg;
+ else
+ return converterr("(unspecified)",
+ arg, msgbuf, bufsize);
+
+ }
+ else if (*format == '&') {
+ typedef int (*converter)(PyObject *, void *);
+ converter convert = va_arg(*p_va, converter);
+ void *addr = va_arg(*p_va, void *);
+ format++;
+ if (! (*convert)(arg, addr))
+ return converterr("(unspecified)",
+ arg, msgbuf, bufsize);
+ }
+ else {
+ p = va_arg(*p_va, PyObject **);
+ *p = arg;
+ }
+ break;
+ }
+
+ case 'w': { /* memory buffer, read-write access */
+ void **p = va_arg(*p_va, void **);
+ void *res;
+ PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
+ Py_ssize_t count;
+
+ if (pb && pb->bf_releasebuffer && *format != '*')
+ /* Buffer must be released, yet caller does not use
+ the Py_buffer protocol. */
+ return converterr("pinned buffer", arg, msgbuf, bufsize);
+
+ if (pb && pb->bf_getbuffer && *format == '*') {
+ /* Caller is interested in Py_buffer, and the object
+ supports it directly. */
+ format++;
+ if (pb->bf_getbuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
+ PyErr_Clear();
+ return converterr("read-write buffer", arg, msgbuf, bufsize);
+ }
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
+ return converterr("contiguous buffer", arg, msgbuf, bufsize);
+ break;
+ }
+
+ if (pb == NULL ||
+ pb->bf_getwritebuffer == NULL ||
+ pb->bf_getsegcount == NULL)
+ return converterr("read-write buffer", arg, msgbuf, bufsize);
+ if ((*pb->bf_getsegcount)(arg, NULL) != 1)
+ return converterr("single-segment read-write buffer",
+ arg, msgbuf, bufsize);
+ if ((count = pb->bf_getwritebuffer(arg, 0, &res)) < 0)
+ return converterr("(unspecified)", arg, msgbuf, bufsize);
+ if (*format == '*') {
+ PyBuffer_FillInfo((Py_buffer*)p, arg, res, count, 1, 0);
+ format++;
+ }
+ else {
+ *p = res;
+ if (*format == '#') {
+ FETCH_SIZE;
+ STORE_SIZE(count);
+ format++;
+ }
+ }
+ break;
+ }
+
+ case 't': { /* 8-bit character buffer, read-only access */
+ char **p = va_arg(*p_va, char **);
+ PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
+ Py_ssize_t count;
+
+ if (*format++ != '#')
+ return converterr(
+ "invalid use of 't' format character",
+ arg, msgbuf, bufsize);
+ if (!PyType_HasFeature(arg->ob_type,
+ Py_TPFLAGS_HAVE_GETCHARBUFFER) ||
+ pb == NULL || pb->bf_getcharbuffer == NULL ||
+ pb->bf_getsegcount == NULL)
+ return converterr(
+ "string or read-only character buffer",
+ arg, msgbuf, bufsize);
+
+ if (pb->bf_getsegcount(arg, NULL) != 1)
+ return converterr(
+ "string or single-segment read-only buffer",
+ arg, msgbuf, bufsize);
+
+ if (pb->bf_releasebuffer)
+ return converterr(
+ "string or pinned buffer",
+ arg, msgbuf, bufsize);
+
+ count = pb->bf_getcharbuffer(arg, 0, p);
+ if (count < 0)
+ return converterr("(unspecified)", arg, msgbuf, bufsize);
+ {
+ FETCH_SIZE;
+ STORE_SIZE(count);
+ }
+ break;
+ }
+
+ default:
+ return converterr("(impossible<bad format char>)", arg, msgbuf, bufsize);
+
+ }
+
+ *p_format = format;
+ return NULL;
+}
+
+static Py_ssize_t
+convertbuffer(PyObject *arg, void **p, char **errmsg)
+{
+ PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
+ Py_ssize_t count;
+ if (pb == NULL ||
+ pb->bf_getreadbuffer == NULL ||
+ pb->bf_getsegcount == NULL ||
+ pb->bf_releasebuffer != NULL) {
+ *errmsg = "string or read-only buffer";
+ return -1;
+ }
+ if ((*pb->bf_getsegcount)(arg, NULL) != 1) {
+ *errmsg = "string or single-segment read-only buffer";
+ return -1;
+ }
+ if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) {
+ *errmsg = "(unspecified)";
+ }
+ return count;
+}
+
+static int
+getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
+{
+ void *buf;
+ Py_ssize_t count;
+ PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
+ if (pb == NULL) {
+ *errmsg = "string or buffer";
+ return -1;
+ }
+ if (pb->bf_getbuffer) {
+ if (pb->bf_getbuffer(arg, view, 0) < 0) {
+ *errmsg = "convertible to a buffer";
+ return -1;
+ }
+ if (!PyBuffer_IsContiguous(view, 'C')) {
+ *errmsg = "contiguous buffer";
+ return -1;
+ }
+ return 0;
+ }
+
+ count = convertbuffer(arg, &buf, errmsg);
+ if (count < 0) {
+ *errmsg = "convertible to a buffer";
+ return count;
+ }
+ PyBuffer_FillInfo(view, arg, buf, count, 1, 0);
+ return 0;
+}
+
+/* Support for keyword arguments donated by
+ Geoff Philbrick <philbric@delphi.hks.com> */
+
+/* Return false (0) for error, else true. */
+int
+PyArg_ParseTupleAndKeywords(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, ...)
+{
+ int retval;
+ va_list va;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_start(va, kwlist);
+ retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+int
+_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, ...)
+{
+ int retval;
+ va_list va;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_start(va, kwlist);
+ retval = vgetargskeywords(args, keywords, format,
+ kwlist, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+PyArg_VaParseTupleAndKeywords(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+#ifdef VA_LIST_IS_ARRAY
+ memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(lva, va);
+#else
+ lva = va;
+#endif
+#endif
+
+ retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0);
+ return retval;
+}
+
+int
+_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+#ifdef VA_LIST_IS_ARRAY
+ memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(lva, va);
+#else
+ lva = va;
+#endif
+#endif
+
+ retval = vgetargskeywords(args, keywords, format,
+ kwlist, &lva, FLAG_SIZE_T);
+ return retval;
+}
+
+#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
+
+static int
+vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
+ char **kwlist, va_list *p_va, int flags)
+{
+ char msgbuf[512];
+ int levels[32];
+ const char *fname, *msg, *custom_msg, *keyword;
+ int min = INT_MAX;
+ int i, len, nargs, nkeywords;
+ PyObject *freelist = NULL, *current_arg;
+
+ assert(args != NULL && PyTuple_Check(args));
+ assert(keywords == NULL || PyDict_Check(keywords));
+ assert(format != NULL);
+ assert(kwlist != NULL);
+ assert(p_va != NULL);
+
+ /* grab the function name or custom error msg first (mutually exclusive) */
+ fname = strchr(format, ':');
+ if (fname) {
+ fname++;
+ custom_msg = NULL;
+ }
+ else {
+ custom_msg = strchr(format,';');
+ if (custom_msg)
+ custom_msg++;
+ }
+
+ /* scan kwlist and get greatest possible nbr of args */
+ for (len=0; kwlist[len]; len++)
+ continue;
+
+ nargs = PyTuple_GET_SIZE(args);
+ nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords);
+ if (nargs + nkeywords > len) {
+ PyErr_Format(PyExc_TypeError, "%s%s takes at most %d "
+ "argument%s (%d given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ len,
+ (len == 1) ? "" : "s",
+ nargs + nkeywords);
+ return 0;
+ }
+
+ /* convert tuple args and keyword args in same loop, using kwlist to drive process */
+ for (i = 0; i < len; i++) {
+ keyword = kwlist[i];
+ if (*format == '|') {
+ min = i;
+ format++;
+ }
+ if (IS_END_OF_FORMAT(*format)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "More keyword list entries (%d) than "
+ "format specifiers (%d)", len, i);
+ return cleanreturn(0, freelist);
+ }
+ current_arg = NULL;
+ if (nkeywords) {
+ current_arg = PyDict_GetItemString(keywords, keyword);
+ }
+ if (current_arg) {
+ --nkeywords;
+ if (i < nargs) {
+ /* arg present in tuple and in dict */
+ PyErr_Format(PyExc_TypeError,
+ "Argument given by name ('%s') "
+ "and position (%d)",
+ keyword, i+1);
+ return cleanreturn(0, freelist);
+ }
+ }
+ else if (nkeywords && PyErr_Occurred())
+ return cleanreturn(0, freelist);
+ else if (i < nargs)
+ current_arg = PyTuple_GET_ITEM(args, i);
+
+ if (current_arg) {
+ msg = convertitem(current_arg, &format, p_va, flags,
+ levels, msgbuf, sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, fname, custom_msg);
+ return cleanreturn(0, freelist);
+ }
+ continue;
+ }
+
+ if (i < min) {
+ PyErr_Format(PyExc_TypeError, "Required argument "
+ "'%s' (pos %d) not found",
+ keyword, i+1);
+ return cleanreturn(0, freelist);
+ }
+ /* 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 (!nkeywords)
+ return cleanreturn(1, freelist);
+
+ /* We are into optional args, skip thru to any remaining
+ * keyword args */
+ msg = skipitem(&format, p_va, flags);
+ if (msg) {
+ PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg,
+ format);
+ return cleanreturn(0, freelist);
+ }
+ }
+
+ if (!IS_END_OF_FORMAT(*format) && *format != '|') {
+ PyErr_Format(PyExc_RuntimeError,
+ "more argument specifiers than keyword list entries "
+ "(remaining format:'%s')", format);
+ return cleanreturn(0, freelist);
+ }
+
+ /* make sure there are no extraneous keyword arguments */
+ if (nkeywords > 0) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(keywords, &pos, &key, &value)) {
+ int match = 0;
+ char *ks;
+ if (!PyString_Check(key)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keywords must be strings");
+ return cleanreturn(0, freelist);
+ }
+ ks = PyString_AsString(key);
+ for (i = 0; i < len; i++) {
+ if (!strcmp(ks, kwlist[i])) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%s' is an invalid keyword "
+ "argument for this function",
+ ks);
+ return cleanreturn(0, freelist);
+ }
+ }
+ }
+
+ return cleanreturn(1, freelist);
+}
+
+
+static char *
+skipitem(const char **p_format, va_list *p_va, int flags)
+{
+ const char *format = *p_format;
+ char c = *format++;
+
+ switch (c) {
+
+ /* simple codes
+ * The individual types (second arg of va_arg) are irrelevant */
+
+ case 'b': /* byte -- very short int */
+ case 'B': /* byte as bitfield */
+ case 'h': /* short int */
+ case 'H': /* short int as bitfield */
+ case 'i': /* int */
+ case 'I': /* int sized bitfield */
+ case 'l': /* long int */
+ case 'k': /* long int sized bitfield */
+#ifdef HAVE_LONG_LONG
+ case 'L': /* PY_LONG_LONG */
+ case 'K': /* PY_LONG_LONG sized bitfield */
+#endif
+ case 'f': /* float */
+ case 'd': /* double */
+#ifndef WITHOUT_COMPLEX
+ case 'D': /* complex double */
+#endif
+ case 'c': /* char */
+ {
+ (void) va_arg(*p_va, void *);
+ break;
+ }
+
+ case 'n': /* Py_ssize_t */
+ {
+ (void) va_arg(*p_va, Py_ssize_t *);
+ break;
+ }
+
+ /* string codes */
+
+ case 'e': /* string with encoding */
+ {
+ (void) va_arg(*p_va, const char *);
+ if (!(*format == 's' || *format == 't'))
+ /* after 'e', only 's' and 't' is allowed */
+ goto err;
+ format++;
+ /* explicit fallthrough to string cases */
+ }
+
+ case 's': /* string */
+ case 'z': /* string or None */
+#ifdef Py_USING_UNICODE
+ case 'u': /* unicode string */
+#endif
+ case 't': /* buffer, read-only */
+ case 'w': /* buffer, read-write */
+ {
+ (void) va_arg(*p_va, char **);
+ if (*format == '#') {
+ if (flags & FLAG_SIZE_T)
+ (void) va_arg(*p_va, Py_ssize_t *);
+ else
+ (void) va_arg(*p_va, int *);
+ format++;
+ } else if ((c == 's' || c == 'z' || c == 'w') && *format == '*') {
+ format++;
+ }
+ break;
+ }
+
+ /* object codes */
+
+ case 'S': /* string object */
+#ifdef Py_USING_UNICODE
+ case 'U': /* unicode string object */
+#endif
+ {
+ (void) va_arg(*p_va, PyObject **);
+ break;
+ }
+
+ case 'O': /* object */
+ {
+ if (*format == '!') {
+ format++;
+ (void) va_arg(*p_va, PyTypeObject*);
+ (void) va_arg(*p_va, PyObject **);
+ }
+ else if (*format == '&') {
+ typedef int (*converter)(PyObject *, void *);
+ (void) va_arg(*p_va, converter);
+ (void) va_arg(*p_va, void *);
+ format++;
+ }
+ else {
+ (void) va_arg(*p_va, PyObject **);
+ }
+ break;
+ }
+
+ case '(': /* bypass tuple, not handled at all previously */
+ {
+ char *msg;
+ for (;;) {
+ if (*format==')')
+ break;
+ if (IS_END_OF_FORMAT(*format))
+ return "Unmatched left paren in format "
+ "string";
+ msg = skipitem(&format, p_va, flags);
+ if (msg)
+ return msg;
+ }
+ format++;
+ break;
+ }
+
+ case ')':
+ return "Unmatched right paren in format string";
+
+ default:
+err:
+ return "impossible<bad format char>";
+
+ }
+
+ *p_format = format;
+ return NULL;
+}
+
+
+int
+PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+{
+ Py_ssize_t i, l;
+ PyObject **o;
+ va_list vargs;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, max);
+#else
+ va_start(vargs);
+#endif
+
+ assert(min >= 0);
+ assert(min <= max);
+ if (!PyTuple_Check(args)) {
+ va_end(vargs);
+ PyErr_SetString(PyExc_SystemError,
+ "PyArg_UnpackTuple() argument list is not a tuple");
+ return 0;
+ }
+ l = PyTuple_GET_SIZE(args);
+ if (l < min) {
+ if (name != NULL)
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s expected %s%zd arguments, got %zd",
+ name, (min == max ? "" : "at least "), min, l);
+ else
+ PyErr_Format(
+ PyExc_TypeError,
+ "unpacked tuple should have %s%zd elements,"
+ " but has %zd",
+ (min == max ? "" : "at least "), min, l);
+ va_end(vargs);
+ return 0;
+ }
+ if (l > max) {
+ if (name != NULL)
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s expected %s%zd arguments, got %zd",
+ name, (min == max ? "" : "at most "), max, l);
+ else
+ PyErr_Format(
+ PyExc_TypeError,
+ "unpacked tuple should have %s%zd elements,"
+ " but has %zd",
+ (min == max ? "" : "at most "), max, l);
+ va_end(vargs);
+ return 0;
+ }
+ for (i = 0; i < l; i++) {
+ o = va_arg(vargs, PyObject **);
+ *o = PyTuple_GET_ITEM(args, i);
+ }
+ va_end(vargs);
+ return 1;
+}
+
+
+/* For type constructors that don't take keyword args
+ *
+ * Sets a TypeError and returns 0 if the kwds dict is
+ * not empty, returns 1 otherwise
+ */
+int
+_PyArg_NoKeywords(const char *funcname, PyObject *kw)
+{
+ if (kw == NULL)
+ return 1;
+ if (!PyDict_CheckExact(kw)) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+ if (PyDict_Size(kw) == 0)
+ return 1;
+
+ PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments",
+ funcname);
+ return 0;
+}
+#ifdef __cplusplus
+};
+#endif
diff --git a/contrib/tools/python/src/Python/getcompiler.c b/contrib/tools/python/src/Python/getcompiler.c
new file mode 100644
index 0000000000..9d9c33ac2d
--- /dev/null
+++ b/contrib/tools/python/src/Python/getcompiler.c
@@ -0,0 +1,28 @@
+
+/* Return the compiler identification, if possible. */
+
+#include "Python.h"
+
+#ifndef COMPILER
+
+#ifdef __GNUC__
+#define COMPILER "\n[GCC " __VERSION__ "]"
+#endif
+
+#endif /* !COMPILER */
+
+#ifndef COMPILER
+
+#ifdef __cplusplus
+#define COMPILER "[C++]"
+#else
+#define COMPILER "[C]"
+#endif
+
+#endif /* !COMPILER */
+
+const char *
+Py_GetCompiler(void)
+{
+ return COMPILER;
+}
diff --git a/contrib/tools/python/src/Python/getcopyright.c b/contrib/tools/python/src/Python/getcopyright.c
new file mode 100644
index 0000000000..0ef16d0923
--- /dev/null
+++ b/contrib/tools/python/src/Python/getcopyright.c
@@ -0,0 +1,23 @@
+/* Return the copyright string. This is updated manually. */
+
+#include "Python.h"
+
+static char cprt[] =
+"\
+Copyright (c) 2001-2019 Python Software Foundation.\n\
+All Rights Reserved.\n\
+\n\
+Copyright (c) 2000 BeOpen.com.\n\
+All Rights Reserved.\n\
+\n\
+Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\
+All Rights Reserved.\n\
+\n\
+Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\
+All Rights Reserved.";
+
+const char *
+Py_GetCopyright(void)
+{
+ return cprt;
+}
diff --git a/contrib/tools/python/src/Python/getopt.c b/contrib/tools/python/src/Python/getopt.c
new file mode 100644
index 0000000000..af5b03c4f4
--- /dev/null
+++ b/contrib/tools/python/src/Python/getopt.c
@@ -0,0 +1,136 @@
+/*---------------------------------------------------------------------------*
+ * <RCS keywords>
+ *
+ * C++ Library
+ *
+ * Copyright 1992-1994, David Gottner
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice, this permission notice and
+ * the following disclaimer notice appear unmodified in all copies.
+ *
+ * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Nevertheless, I would like to know about bugs in this library or
+ * suggestions for improvment. Send bug reports and feedback to
+ * davegottner@delphi.com.
+ *---------------------------------------------------------------------------*/
+
+/* Modified to support --help and --version, as well as /? on Windows
+ * by Georg Brandl. */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _PyOS_opterr = 1; /* generate error messages */
+int _PyOS_optind = 1; /* index into argv array */
+char *_PyOS_optarg = NULL; /* optional argument */
+static char *opt_ptr = "";
+
+void _PyOS_ResetGetOpt(void)
+{
+ _PyOS_opterr = 1;
+ _PyOS_optind = 1;
+ _PyOS_optarg = NULL;
+ opt_ptr = "";
+}
+
+int _PyOS_GetOpt(int argc, char **argv, char *optstring)
+{
+ char *ptr;
+ int option;
+
+ if (*opt_ptr == '\0') {
+
+ if (_PyOS_optind >= argc)
+ return -1;
+#ifdef MS_WINDOWS
+ else if (strcmp(argv[_PyOS_optind], "/?") == 0) {
+ ++_PyOS_optind;
+ return 'h';
+ }
+#endif
+
+ else if (argv[_PyOS_optind][0] != '-' ||
+ argv[_PyOS_optind][1] == '\0' /* lone dash */ )
+ return -1;
+
+ else if (strcmp(argv[_PyOS_optind], "--") == 0) {
+ ++_PyOS_optind;
+ return -1;
+ }
+
+ else if (strcmp(argv[_PyOS_optind], "--help") == 0) {
+ ++_PyOS_optind;
+ return 'h';
+ }
+
+ else if (strcmp(argv[_PyOS_optind], "--version") == 0) {
+ ++_PyOS_optind;
+ return 'V';
+ }
+
+
+ opt_ptr = &argv[_PyOS_optind++][1];
+ }
+
+ if ((option = *opt_ptr++) == '\0')
+ return -1;
+
+ if (option == 'J') {
+ if (_PyOS_opterr)
+ fprintf(stderr, "-J is reserved for Jython\n");
+ return '_';
+ }
+
+ if (option == 'X') {
+ if (_PyOS_opterr)
+ fprintf(stderr,
+ "-X is reserved for implementation-specific arguments\n");
+ return '_';
+ }
+
+ if ((ptr = strchr(optstring, option)) == NULL) {
+ if (_PyOS_opterr)
+ fprintf(stderr, "Unknown option: -%c\n", option);
+
+ return '_';
+ }
+
+ if (*(ptr + 1) == ':') {
+ if (*opt_ptr != '\0') {
+ _PyOS_optarg = opt_ptr;
+ opt_ptr = "";
+ }
+
+ else {
+ if (_PyOS_optind >= argc) {
+ if (_PyOS_opterr)
+ fprintf(stderr,
+ "Argument expected for the -%c option\n", option);
+ return '_';
+ }
+
+ _PyOS_optarg = argv[_PyOS_optind++];
+ }
+ }
+
+ return option;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/contrib/tools/python/src/Python/getplatform.c b/contrib/tools/python/src/Python/getplatform.c
new file mode 100644
index 0000000000..68991402b5
--- /dev/null
+++ b/contrib/tools/python/src/Python/getplatform.c
@@ -0,0 +1,12 @@
+
+#include "Python.h"
+
+#ifndef PLATFORM
+#define PLATFORM "unknown"
+#endif
+
+const char *
+Py_GetPlatform(void)
+{
+ return PLATFORM;
+}
diff --git a/contrib/tools/python/src/Python/getversion.c b/contrib/tools/python/src/Python/getversion.c
new file mode 100644
index 0000000000..7bd6efd0a0
--- /dev/null
+++ b/contrib/tools/python/src/Python/getversion.c
@@ -0,0 +1,15 @@
+
+/* Return the full version string. */
+
+#include "Python.h"
+
+#include "patchlevel.h"
+
+const char *
+Py_GetVersion(void)
+{
+ static char version[250];
+ PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s",
+ PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
+ return version;
+}
diff --git a/contrib/tools/python/src/Python/graminit.c b/contrib/tools/python/src/Python/graminit.c
new file mode 100644
index 0000000000..5db6bb5e53
--- /dev/null
+++ b/contrib/tools/python/src/Python/graminit.c
@@ -0,0 +1,2177 @@
+/* Generated by Parser/pgen */
+
+#include "pgenheaders.h"
+#include "grammar.h"
+PyAPI_DATA(grammar) _PyParser_Grammar;
+static arc arcs_0_0[3] = {
+ {2, 1},
+ {3, 1},
+ {4, 2},
+};
+static arc arcs_0_1[1] = {
+ {0, 1},
+};
+static arc arcs_0_2[1] = {
+ {2, 1},
+};
+static state states_0[3] = {
+ {3, arcs_0_0},
+ {1, arcs_0_1},
+ {1, arcs_0_2},
+};
+static arc arcs_1_0[3] = {
+ {2, 0},
+ {6, 0},
+ {7, 1},
+};
+static arc arcs_1_1[1] = {
+ {0, 1},
+};
+static state states_1[2] = {
+ {3, arcs_1_0},
+ {1, arcs_1_1},
+};
+static arc arcs_2_0[1] = {
+ {9, 1},
+};
+static arc arcs_2_1[2] = {
+ {2, 1},
+ {7, 2},
+};
+static arc arcs_2_2[1] = {
+ {0, 2},
+};
+static state states_2[3] = {
+ {1, arcs_2_0},
+ {2, arcs_2_1},
+ {1, arcs_2_2},
+};
+static arc arcs_3_0[1] = {
+ {11, 1},
+};
+static arc arcs_3_1[1] = {
+ {12, 2},
+};
+static arc arcs_3_2[2] = {
+ {13, 3},
+ {2, 4},
+};
+static arc arcs_3_3[2] = {
+ {14, 5},
+ {15, 6},
+};
+static arc arcs_3_4[1] = {
+ {0, 4},
+};
+static arc arcs_3_5[1] = {
+ {15, 6},
+};
+static arc arcs_3_6[1] = {
+ {2, 4},
+};
+static state states_3[7] = {
+ {1, arcs_3_0},
+ {1, arcs_3_1},
+ {2, arcs_3_2},
+ {2, arcs_3_3},
+ {1, arcs_3_4},
+ {1, arcs_3_5},
+ {1, arcs_3_6},
+};
+static arc arcs_4_0[1] = {
+ {10, 1},
+};
+static arc arcs_4_1[2] = {
+ {10, 1},
+ {0, 1},
+};
+static state states_4[2] = {
+ {1, arcs_4_0},
+ {2, arcs_4_1},
+};
+static arc arcs_5_0[1] = {
+ {16, 1},
+};
+static arc arcs_5_1[2] = {
+ {18, 2},
+ {19, 2},
+};
+static arc arcs_5_2[1] = {
+ {0, 2},
+};
+static state states_5[3] = {
+ {1, arcs_5_0},
+ {2, arcs_5_1},
+ {1, arcs_5_2},
+};
+static arc arcs_6_0[1] = {
+ {20, 1},
+};
+static arc arcs_6_1[1] = {
+ {21, 2},
+};
+static arc arcs_6_2[1] = {
+ {22, 3},
+};
+static arc arcs_6_3[1] = {
+ {23, 4},
+};
+static arc arcs_6_4[1] = {
+ {24, 5},
+};
+static arc arcs_6_5[1] = {
+ {0, 5},
+};
+static state states_6[6] = {
+ {1, arcs_6_0},
+ {1, arcs_6_1},
+ {1, arcs_6_2},
+ {1, arcs_6_3},
+ {1, arcs_6_4},
+ {1, arcs_6_5},
+};
+static arc arcs_7_0[1] = {
+ {13, 1},
+};
+static arc arcs_7_1[2] = {
+ {25, 2},
+ {15, 3},
+};
+static arc arcs_7_2[1] = {
+ {15, 3},
+};
+static arc arcs_7_3[1] = {
+ {0, 3},
+};
+static state states_7[4] = {
+ {1, arcs_7_0},
+ {2, arcs_7_1},
+ {1, arcs_7_2},
+ {1, arcs_7_3},
+};
+static arc arcs_8_0[3] = {
+ {26, 1},
+ {30, 2},
+ {31, 3},
+};
+static arc arcs_8_1[3] = {
+ {27, 4},
+ {29, 5},
+ {0, 1},
+};
+static arc arcs_8_2[1] = {
+ {21, 6},
+};
+static arc arcs_8_3[1] = {
+ {21, 7},
+};
+static arc arcs_8_4[1] = {
+ {28, 8},
+};
+static arc arcs_8_5[4] = {
+ {26, 1},
+ {30, 2},
+ {31, 3},
+ {0, 5},
+};
+static arc arcs_8_6[2] = {
+ {29, 9},
+ {0, 6},
+};
+static arc arcs_8_7[1] = {
+ {0, 7},
+};
+static arc arcs_8_8[2] = {
+ {29, 5},
+ {0, 8},
+};
+static arc arcs_8_9[1] = {
+ {31, 3},
+};
+static state states_8[10] = {
+ {3, arcs_8_0},
+ {3, arcs_8_1},
+ {1, arcs_8_2},
+ {1, arcs_8_3},
+ {1, arcs_8_4},
+ {4, arcs_8_5},
+ {2, arcs_8_6},
+ {1, arcs_8_7},
+ {2, arcs_8_8},
+ {1, arcs_8_9},
+};
+static arc arcs_9_0[2] = {
+ {21, 1},
+ {13, 2},
+};
+static arc arcs_9_1[1] = {
+ {0, 1},
+};
+static arc arcs_9_2[1] = {
+ {32, 3},
+};
+static arc arcs_9_3[1] = {
+ {15, 1},
+};
+static state states_9[4] = {
+ {2, arcs_9_0},
+ {1, arcs_9_1},
+ {1, arcs_9_2},
+ {1, arcs_9_3},
+};
+static arc arcs_10_0[1] = {
+ {26, 1},
+};
+static arc arcs_10_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_10_2[2] = {
+ {26, 1},
+ {0, 2},
+};
+static state states_10[3] = {
+ {1, arcs_10_0},
+ {2, arcs_10_1},
+ {2, arcs_10_2},
+};
+static arc arcs_11_0[2] = {
+ {3, 1},
+ {4, 1},
+};
+static arc arcs_11_1[1] = {
+ {0, 1},
+};
+static state states_11[2] = {
+ {2, arcs_11_0},
+ {1, arcs_11_1},
+};
+static arc arcs_12_0[1] = {
+ {33, 1},
+};
+static arc arcs_12_1[2] = {
+ {34, 2},
+ {2, 3},
+};
+static arc arcs_12_2[2] = {
+ {33, 1},
+ {2, 3},
+};
+static arc arcs_12_3[1] = {
+ {0, 3},
+};
+static state states_12[4] = {
+ {1, arcs_12_0},
+ {2, arcs_12_1},
+ {2, arcs_12_2},
+ {1, arcs_12_3},
+};
+static arc arcs_13_0[9] = {
+ {35, 1},
+ {36, 1},
+ {37, 1},
+ {38, 1},
+ {39, 1},
+ {40, 1},
+ {41, 1},
+ {42, 1},
+ {43, 1},
+};
+static arc arcs_13_1[1] = {
+ {0, 1},
+};
+static state states_13[2] = {
+ {9, arcs_13_0},
+ {1, arcs_13_1},
+};
+static arc arcs_14_0[1] = {
+ {9, 1},
+};
+static arc arcs_14_1[3] = {
+ {44, 2},
+ {27, 3},
+ {0, 1},
+};
+static arc arcs_14_2[2] = {
+ {45, 4},
+ {9, 4},
+};
+static arc arcs_14_3[2] = {
+ {45, 5},
+ {9, 5},
+};
+static arc arcs_14_4[1] = {
+ {0, 4},
+};
+static arc arcs_14_5[2] = {
+ {27, 3},
+ {0, 5},
+};
+static state states_14[6] = {
+ {1, arcs_14_0},
+ {3, arcs_14_1},
+ {2, arcs_14_2},
+ {2, arcs_14_3},
+ {1, arcs_14_4},
+ {2, arcs_14_5},
+};
+static arc arcs_15_0[12] = {
+ {46, 1},
+ {47, 1},
+ {48, 1},
+ {49, 1},
+ {50, 1},
+ {51, 1},
+ {52, 1},
+ {53, 1},
+ {54, 1},
+ {55, 1},
+ {56, 1},
+ {57, 1},
+};
+static arc arcs_15_1[1] = {
+ {0, 1},
+};
+static state states_15[2] = {
+ {12, arcs_15_0},
+ {1, arcs_15_1},
+};
+static arc arcs_16_0[1] = {
+ {58, 1},
+};
+static arc arcs_16_1[3] = {
+ {28, 2},
+ {59, 3},
+ {0, 1},
+};
+static arc arcs_16_2[2] = {
+ {29, 4},
+ {0, 2},
+};
+static arc arcs_16_3[1] = {
+ {28, 5},
+};
+static arc arcs_16_4[2] = {
+ {28, 2},
+ {0, 4},
+};
+static arc arcs_16_5[2] = {
+ {29, 6},
+ {0, 5},
+};
+static arc arcs_16_6[1] = {
+ {28, 7},
+};
+static arc arcs_16_7[2] = {
+ {29, 8},
+ {0, 7},
+};
+static arc arcs_16_8[2] = {
+ {28, 7},
+ {0, 8},
+};
+static state states_16[9] = {
+ {1, arcs_16_0},
+ {3, arcs_16_1},
+ {2, arcs_16_2},
+ {1, arcs_16_3},
+ {2, arcs_16_4},
+ {2, arcs_16_5},
+ {1, arcs_16_6},
+ {2, arcs_16_7},
+ {2, arcs_16_8},
+};
+static arc arcs_17_0[1] = {
+ {60, 1},
+};
+static arc arcs_17_1[1] = {
+ {61, 2},
+};
+static arc arcs_17_2[1] = {
+ {0, 2},
+};
+static state states_17[3] = {
+ {1, arcs_17_0},
+ {1, arcs_17_1},
+ {1, arcs_17_2},
+};
+static arc arcs_18_0[1] = {
+ {62, 1},
+};
+static arc arcs_18_1[1] = {
+ {0, 1},
+};
+static state states_18[2] = {
+ {1, arcs_18_0},
+ {1, arcs_18_1},
+};
+static arc arcs_19_0[5] = {
+ {63, 1},
+ {64, 1},
+ {65, 1},
+ {66, 1},
+ {67, 1},
+};
+static arc arcs_19_1[1] = {
+ {0, 1},
+};
+static state states_19[2] = {
+ {5, arcs_19_0},
+ {1, arcs_19_1},
+};
+static arc arcs_20_0[1] = {
+ {68, 1},
+};
+static arc arcs_20_1[1] = {
+ {0, 1},
+};
+static state states_20[2] = {
+ {1, arcs_20_0},
+ {1, arcs_20_1},
+};
+static arc arcs_21_0[1] = {
+ {69, 1},
+};
+static arc arcs_21_1[1] = {
+ {0, 1},
+};
+static state states_21[2] = {
+ {1, arcs_21_0},
+ {1, arcs_21_1},
+};
+static arc arcs_22_0[1] = {
+ {70, 1},
+};
+static arc arcs_22_1[2] = {
+ {9, 2},
+ {0, 1},
+};
+static arc arcs_22_2[1] = {
+ {0, 2},
+};
+static state states_22[3] = {
+ {1, arcs_22_0},
+ {2, arcs_22_1},
+ {1, arcs_22_2},
+};
+static arc arcs_23_0[1] = {
+ {45, 1},
+};
+static arc arcs_23_1[1] = {
+ {0, 1},
+};
+static state states_23[2] = {
+ {1, arcs_23_0},
+ {1, arcs_23_1},
+};
+static arc arcs_24_0[1] = {
+ {71, 1},
+};
+static arc arcs_24_1[2] = {
+ {28, 2},
+ {0, 1},
+};
+static arc arcs_24_2[2] = {
+ {29, 3},
+ {0, 2},
+};
+static arc arcs_24_3[1] = {
+ {28, 4},
+};
+static arc arcs_24_4[2] = {
+ {29, 5},
+ {0, 4},
+};
+static arc arcs_24_5[1] = {
+ {28, 6},
+};
+static arc arcs_24_6[1] = {
+ {0, 6},
+};
+static state states_24[7] = {
+ {1, arcs_24_0},
+ {2, arcs_24_1},
+ {2, arcs_24_2},
+ {1, arcs_24_3},
+ {2, arcs_24_4},
+ {1, arcs_24_5},
+ {1, arcs_24_6},
+};
+static arc arcs_25_0[2] = {
+ {72, 1},
+ {73, 1},
+};
+static arc arcs_25_1[1] = {
+ {0, 1},
+};
+static state states_25[2] = {
+ {2, arcs_25_0},
+ {1, arcs_25_1},
+};
+static arc arcs_26_0[1] = {
+ {74, 1},
+};
+static arc arcs_26_1[1] = {
+ {75, 2},
+};
+static arc arcs_26_2[1] = {
+ {0, 2},
+};
+static state states_26[3] = {
+ {1, arcs_26_0},
+ {1, arcs_26_1},
+ {1, arcs_26_2},
+};
+static arc arcs_27_0[1] = {
+ {76, 1},
+};
+static arc arcs_27_1[2] = {
+ {77, 2},
+ {12, 3},
+};
+static arc arcs_27_2[3] = {
+ {77, 2},
+ {12, 3},
+ {74, 4},
+};
+static arc arcs_27_3[1] = {
+ {74, 4},
+};
+static arc arcs_27_4[3] = {
+ {30, 5},
+ {13, 6},
+ {78, 5},
+};
+static arc arcs_27_5[1] = {
+ {0, 5},
+};
+static arc arcs_27_6[1] = {
+ {78, 7},
+};
+static arc arcs_27_7[1] = {
+ {15, 5},
+};
+static state states_27[8] = {
+ {1, arcs_27_0},
+ {2, arcs_27_1},
+ {3, arcs_27_2},
+ {1, arcs_27_3},
+ {3, arcs_27_4},
+ {1, arcs_27_5},
+ {1, arcs_27_6},
+ {1, arcs_27_7},
+};
+static arc arcs_28_0[1] = {
+ {21, 1},
+};
+static arc arcs_28_1[2] = {
+ {80, 2},
+ {0, 1},
+};
+static arc arcs_28_2[1] = {
+ {21, 3},
+};
+static arc arcs_28_3[1] = {
+ {0, 3},
+};
+static state states_28[4] = {
+ {1, arcs_28_0},
+ {2, arcs_28_1},
+ {1, arcs_28_2},
+ {1, arcs_28_3},
+};
+static arc arcs_29_0[1] = {
+ {12, 1},
+};
+static arc arcs_29_1[2] = {
+ {80, 2},
+ {0, 1},
+};
+static arc arcs_29_2[1] = {
+ {21, 3},
+};
+static arc arcs_29_3[1] = {
+ {0, 3},
+};
+static state states_29[4] = {
+ {1, arcs_29_0},
+ {2, arcs_29_1},
+ {1, arcs_29_2},
+ {1, arcs_29_3},
+};
+static arc arcs_30_0[1] = {
+ {79, 1},
+};
+static arc arcs_30_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_30_2[2] = {
+ {79, 1},
+ {0, 2},
+};
+static state states_30[3] = {
+ {1, arcs_30_0},
+ {2, arcs_30_1},
+ {2, arcs_30_2},
+};
+static arc arcs_31_0[1] = {
+ {81, 1},
+};
+static arc arcs_31_1[2] = {
+ {29, 0},
+ {0, 1},
+};
+static state states_31[2] = {
+ {1, arcs_31_0},
+ {2, arcs_31_1},
+};
+static arc arcs_32_0[1] = {
+ {21, 1},
+};
+static arc arcs_32_1[2] = {
+ {77, 0},
+ {0, 1},
+};
+static state states_32[2] = {
+ {1, arcs_32_0},
+ {2, arcs_32_1},
+};
+static arc arcs_33_0[1] = {
+ {82, 1},
+};
+static arc arcs_33_1[1] = {
+ {21, 2},
+};
+static arc arcs_33_2[2] = {
+ {29, 1},
+ {0, 2},
+};
+static state states_33[3] = {
+ {1, arcs_33_0},
+ {1, arcs_33_1},
+ {2, arcs_33_2},
+};
+static arc arcs_34_0[1] = {
+ {83, 1},
+};
+static arc arcs_34_1[1] = {
+ {84, 2},
+};
+static arc arcs_34_2[2] = {
+ {85, 3},
+ {0, 2},
+};
+static arc arcs_34_3[1] = {
+ {28, 4},
+};
+static arc arcs_34_4[2] = {
+ {29, 5},
+ {0, 4},
+};
+static arc arcs_34_5[1] = {
+ {28, 6},
+};
+static arc arcs_34_6[1] = {
+ {0, 6},
+};
+static state states_34[7] = {
+ {1, arcs_34_0},
+ {1, arcs_34_1},
+ {2, arcs_34_2},
+ {1, arcs_34_3},
+ {2, arcs_34_4},
+ {1, arcs_34_5},
+ {1, arcs_34_6},
+};
+static arc arcs_35_0[1] = {
+ {86, 1},
+};
+static arc arcs_35_1[1] = {
+ {28, 2},
+};
+static arc arcs_35_2[2] = {
+ {29, 3},
+ {0, 2},
+};
+static arc arcs_35_3[1] = {
+ {28, 4},
+};
+static arc arcs_35_4[1] = {
+ {0, 4},
+};
+static state states_35[5] = {
+ {1, arcs_35_0},
+ {1, arcs_35_1},
+ {2, arcs_35_2},
+ {1, arcs_35_3},
+ {1, arcs_35_4},
+};
+static arc arcs_36_0[8] = {
+ {87, 1},
+ {88, 1},
+ {89, 1},
+ {90, 1},
+ {91, 1},
+ {19, 1},
+ {18, 1},
+ {17, 1},
+};
+static arc arcs_36_1[1] = {
+ {0, 1},
+};
+static state states_36[2] = {
+ {8, arcs_36_0},
+ {1, arcs_36_1},
+};
+static arc arcs_37_0[1] = {
+ {92, 1},
+};
+static arc arcs_37_1[1] = {
+ {28, 2},
+};
+static arc arcs_37_2[1] = {
+ {23, 3},
+};
+static arc arcs_37_3[1] = {
+ {24, 4},
+};
+static arc arcs_37_4[3] = {
+ {93, 1},
+ {94, 5},
+ {0, 4},
+};
+static arc arcs_37_5[1] = {
+ {23, 6},
+};
+static arc arcs_37_6[1] = {
+ {24, 7},
+};
+static arc arcs_37_7[1] = {
+ {0, 7},
+};
+static state states_37[8] = {
+ {1, arcs_37_0},
+ {1, arcs_37_1},
+ {1, arcs_37_2},
+ {1, arcs_37_3},
+ {3, arcs_37_4},
+ {1, arcs_37_5},
+ {1, arcs_37_6},
+ {1, arcs_37_7},
+};
+static arc arcs_38_0[1] = {
+ {95, 1},
+};
+static arc arcs_38_1[1] = {
+ {28, 2},
+};
+static arc arcs_38_2[1] = {
+ {23, 3},
+};
+static arc arcs_38_3[1] = {
+ {24, 4},
+};
+static arc arcs_38_4[2] = {
+ {94, 5},
+ {0, 4},
+};
+static arc arcs_38_5[1] = {
+ {23, 6},
+};
+static arc arcs_38_6[1] = {
+ {24, 7},
+};
+static arc arcs_38_7[1] = {
+ {0, 7},
+};
+static state states_38[8] = {
+ {1, arcs_38_0},
+ {1, arcs_38_1},
+ {1, arcs_38_2},
+ {1, arcs_38_3},
+ {2, arcs_38_4},
+ {1, arcs_38_5},
+ {1, arcs_38_6},
+ {1, arcs_38_7},
+};
+static arc arcs_39_0[1] = {
+ {96, 1},
+};
+static arc arcs_39_1[1] = {
+ {61, 2},
+};
+static arc arcs_39_2[1] = {
+ {85, 3},
+};
+static arc arcs_39_3[1] = {
+ {9, 4},
+};
+static arc arcs_39_4[1] = {
+ {23, 5},
+};
+static arc arcs_39_5[1] = {
+ {24, 6},
+};
+static arc arcs_39_6[2] = {
+ {94, 7},
+ {0, 6},
+};
+static arc arcs_39_7[1] = {
+ {23, 8},
+};
+static arc arcs_39_8[1] = {
+ {24, 9},
+};
+static arc arcs_39_9[1] = {
+ {0, 9},
+};
+static state states_39[10] = {
+ {1, arcs_39_0},
+ {1, arcs_39_1},
+ {1, arcs_39_2},
+ {1, arcs_39_3},
+ {1, arcs_39_4},
+ {1, arcs_39_5},
+ {2, arcs_39_6},
+ {1, arcs_39_7},
+ {1, arcs_39_8},
+ {1, arcs_39_9},
+};
+static arc arcs_40_0[1] = {
+ {97, 1},
+};
+static arc arcs_40_1[1] = {
+ {23, 2},
+};
+static arc arcs_40_2[1] = {
+ {24, 3},
+};
+static arc arcs_40_3[2] = {
+ {98, 4},
+ {99, 5},
+};
+static arc arcs_40_4[1] = {
+ {23, 6},
+};
+static arc arcs_40_5[1] = {
+ {23, 7},
+};
+static arc arcs_40_6[1] = {
+ {24, 8},
+};
+static arc arcs_40_7[1] = {
+ {24, 9},
+};
+static arc arcs_40_8[4] = {
+ {98, 4},
+ {94, 10},
+ {99, 5},
+ {0, 8},
+};
+static arc arcs_40_9[1] = {
+ {0, 9},
+};
+static arc arcs_40_10[1] = {
+ {23, 11},
+};
+static arc arcs_40_11[1] = {
+ {24, 12},
+};
+static arc arcs_40_12[2] = {
+ {99, 5},
+ {0, 12},
+};
+static state states_40[13] = {
+ {1, arcs_40_0},
+ {1, arcs_40_1},
+ {1, arcs_40_2},
+ {2, arcs_40_3},
+ {1, arcs_40_4},
+ {1, arcs_40_5},
+ {1, arcs_40_6},
+ {1, arcs_40_7},
+ {4, arcs_40_8},
+ {1, arcs_40_9},
+ {1, arcs_40_10},
+ {1, arcs_40_11},
+ {2, arcs_40_12},
+};
+static arc arcs_41_0[1] = {
+ {100, 1},
+};
+static arc arcs_41_1[1] = {
+ {101, 2},
+};
+static arc arcs_41_2[2] = {
+ {29, 1},
+ {23, 3},
+};
+static arc arcs_41_3[1] = {
+ {24, 4},
+};
+static arc arcs_41_4[1] = {
+ {0, 4},
+};
+static state states_41[5] = {
+ {1, arcs_41_0},
+ {1, arcs_41_1},
+ {2, arcs_41_2},
+ {1, arcs_41_3},
+ {1, arcs_41_4},
+};
+static arc arcs_42_0[1] = {
+ {28, 1},
+};
+static arc arcs_42_1[2] = {
+ {80, 2},
+ {0, 1},
+};
+static arc arcs_42_2[1] = {
+ {84, 3},
+};
+static arc arcs_42_3[1] = {
+ {0, 3},
+};
+static state states_42[4] = {
+ {1, arcs_42_0},
+ {2, arcs_42_1},
+ {1, arcs_42_2},
+ {1, arcs_42_3},
+};
+static arc arcs_43_0[1] = {
+ {102, 1},
+};
+static arc arcs_43_1[2] = {
+ {28, 2},
+ {0, 1},
+};
+static arc arcs_43_2[3] = {
+ {80, 3},
+ {29, 3},
+ {0, 2},
+};
+static arc arcs_43_3[1] = {
+ {28, 4},
+};
+static arc arcs_43_4[1] = {
+ {0, 4},
+};
+static state states_43[5] = {
+ {1, arcs_43_0},
+ {2, arcs_43_1},
+ {3, arcs_43_2},
+ {1, arcs_43_3},
+ {1, arcs_43_4},
+};
+static arc arcs_44_0[2] = {
+ {3, 1},
+ {2, 2},
+};
+static arc arcs_44_1[1] = {
+ {0, 1},
+};
+static arc arcs_44_2[1] = {
+ {103, 3},
+};
+static arc arcs_44_3[1] = {
+ {6, 4},
+};
+static arc arcs_44_4[2] = {
+ {6, 4},
+ {104, 1},
+};
+static state states_44[5] = {
+ {2, arcs_44_0},
+ {1, arcs_44_1},
+ {1, arcs_44_2},
+ {1, arcs_44_3},
+ {2, arcs_44_4},
+};
+static arc arcs_45_0[1] = {
+ {106, 1},
+};
+static arc arcs_45_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_45_2[1] = {
+ {106, 3},
+};
+static arc arcs_45_3[2] = {
+ {29, 4},
+ {0, 3},
+};
+static arc arcs_45_4[2] = {
+ {106, 3},
+ {0, 4},
+};
+static state states_45[5] = {
+ {1, arcs_45_0},
+ {2, arcs_45_1},
+ {1, arcs_45_2},
+ {2, arcs_45_3},
+ {2, arcs_45_4},
+};
+static arc arcs_46_0[2] = {
+ {107, 1},
+ {108, 1},
+};
+static arc arcs_46_1[1] = {
+ {0, 1},
+};
+static state states_46[2] = {
+ {2, arcs_46_0},
+ {1, arcs_46_1},
+};
+static arc arcs_47_0[1] = {
+ {109, 1},
+};
+static arc arcs_47_1[2] = {
+ {25, 2},
+ {23, 3},
+};
+static arc arcs_47_2[1] = {
+ {23, 3},
+};
+static arc arcs_47_3[1] = {
+ {106, 4},
+};
+static arc arcs_47_4[1] = {
+ {0, 4},
+};
+static state states_47[5] = {
+ {1, arcs_47_0},
+ {2, arcs_47_1},
+ {1, arcs_47_2},
+ {1, arcs_47_3},
+ {1, arcs_47_4},
+};
+static arc arcs_48_0[2] = {
+ {107, 1},
+ {110, 2},
+};
+static arc arcs_48_1[2] = {
+ {92, 3},
+ {0, 1},
+};
+static arc arcs_48_2[1] = {
+ {0, 2},
+};
+static arc arcs_48_3[1] = {
+ {107, 4},
+};
+static arc arcs_48_4[1] = {
+ {94, 5},
+};
+static arc arcs_48_5[1] = {
+ {28, 2},
+};
+static state states_48[6] = {
+ {2, arcs_48_0},
+ {2, arcs_48_1},
+ {1, arcs_48_2},
+ {1, arcs_48_3},
+ {1, arcs_48_4},
+ {1, arcs_48_5},
+};
+static arc arcs_49_0[1] = {
+ {111, 1},
+};
+static arc arcs_49_1[2] = {
+ {112, 0},
+ {0, 1},
+};
+static state states_49[2] = {
+ {1, arcs_49_0},
+ {2, arcs_49_1},
+};
+static arc arcs_50_0[1] = {
+ {113, 1},
+};
+static arc arcs_50_1[2] = {
+ {114, 0},
+ {0, 1},
+};
+static state states_50[2] = {
+ {1, arcs_50_0},
+ {2, arcs_50_1},
+};
+static arc arcs_51_0[2] = {
+ {115, 1},
+ {116, 2},
+};
+static arc arcs_51_1[1] = {
+ {113, 2},
+};
+static arc arcs_51_2[1] = {
+ {0, 2},
+};
+static state states_51[3] = {
+ {2, arcs_51_0},
+ {1, arcs_51_1},
+ {1, arcs_51_2},
+};
+static arc arcs_52_0[1] = {
+ {84, 1},
+};
+static arc arcs_52_1[2] = {
+ {117, 0},
+ {0, 1},
+};
+static state states_52[2] = {
+ {1, arcs_52_0},
+ {2, arcs_52_1},
+};
+static arc arcs_53_0[10] = {
+ {118, 1},
+ {119, 1},
+ {120, 1},
+ {121, 1},
+ {122, 1},
+ {123, 1},
+ {124, 1},
+ {85, 1},
+ {115, 2},
+ {125, 3},
+};
+static arc arcs_53_1[1] = {
+ {0, 1},
+};
+static arc arcs_53_2[1] = {
+ {85, 1},
+};
+static arc arcs_53_3[2] = {
+ {115, 1},
+ {0, 3},
+};
+static state states_53[4] = {
+ {10, arcs_53_0},
+ {1, arcs_53_1},
+ {1, arcs_53_2},
+ {2, arcs_53_3},
+};
+static arc arcs_54_0[1] = {
+ {126, 1},
+};
+static arc arcs_54_1[2] = {
+ {127, 0},
+ {0, 1},
+};
+static state states_54[2] = {
+ {1, arcs_54_0},
+ {2, arcs_54_1},
+};
+static arc arcs_55_0[1] = {
+ {128, 1},
+};
+static arc arcs_55_1[2] = {
+ {129, 0},
+ {0, 1},
+};
+static state states_55[2] = {
+ {1, arcs_55_0},
+ {2, arcs_55_1},
+};
+static arc arcs_56_0[1] = {
+ {130, 1},
+};
+static arc arcs_56_1[2] = {
+ {131, 0},
+ {0, 1},
+};
+static state states_56[2] = {
+ {1, arcs_56_0},
+ {2, arcs_56_1},
+};
+static arc arcs_57_0[1] = {
+ {132, 1},
+};
+static arc arcs_57_1[3] = {
+ {133, 0},
+ {59, 0},
+ {0, 1},
+};
+static state states_57[2] = {
+ {1, arcs_57_0},
+ {3, arcs_57_1},
+};
+static arc arcs_58_0[1] = {
+ {134, 1},
+};
+static arc arcs_58_1[3] = {
+ {135, 0},
+ {136, 0},
+ {0, 1},
+};
+static state states_58[2] = {
+ {1, arcs_58_0},
+ {3, arcs_58_1},
+};
+static arc arcs_59_0[1] = {
+ {137, 1},
+};
+static arc arcs_59_1[5] = {
+ {30, 0},
+ {138, 0},
+ {139, 0},
+ {140, 0},
+ {0, 1},
+};
+static state states_59[2] = {
+ {1, arcs_59_0},
+ {5, arcs_59_1},
+};
+static arc arcs_60_0[4] = {
+ {135, 1},
+ {136, 1},
+ {141, 1},
+ {142, 2},
+};
+static arc arcs_60_1[1] = {
+ {137, 2},
+};
+static arc arcs_60_2[1] = {
+ {0, 2},
+};
+static state states_60[3] = {
+ {4, arcs_60_0},
+ {1, arcs_60_1},
+ {1, arcs_60_2},
+};
+static arc arcs_61_0[1] = {
+ {143, 1},
+};
+static arc arcs_61_1[3] = {
+ {144, 1},
+ {31, 2},
+ {0, 1},
+};
+static arc arcs_61_2[1] = {
+ {137, 3},
+};
+static arc arcs_61_3[1] = {
+ {0, 3},
+};
+static state states_61[4] = {
+ {1, arcs_61_0},
+ {3, arcs_61_1},
+ {1, arcs_61_2},
+ {1, arcs_61_3},
+};
+static arc arcs_62_0[7] = {
+ {13, 1},
+ {146, 2},
+ {149, 3},
+ {152, 4},
+ {21, 5},
+ {154, 5},
+ {155, 6},
+};
+static arc arcs_62_1[3] = {
+ {45, 7},
+ {145, 7},
+ {15, 5},
+};
+static arc arcs_62_2[2] = {
+ {147, 8},
+ {148, 5},
+};
+static arc arcs_62_3[2] = {
+ {150, 9},
+ {151, 5},
+};
+static arc arcs_62_4[1] = {
+ {153, 10},
+};
+static arc arcs_62_5[1] = {
+ {0, 5},
+};
+static arc arcs_62_6[2] = {
+ {155, 6},
+ {0, 6},
+};
+static arc arcs_62_7[1] = {
+ {15, 5},
+};
+static arc arcs_62_8[1] = {
+ {148, 5},
+};
+static arc arcs_62_9[1] = {
+ {151, 5},
+};
+static arc arcs_62_10[1] = {
+ {152, 5},
+};
+static state states_62[11] = {
+ {7, arcs_62_0},
+ {3, arcs_62_1},
+ {2, arcs_62_2},
+ {2, arcs_62_3},
+ {1, arcs_62_4},
+ {1, arcs_62_5},
+ {2, arcs_62_6},
+ {1, arcs_62_7},
+ {1, arcs_62_8},
+ {1, arcs_62_9},
+ {1, arcs_62_10},
+};
+static arc arcs_63_0[1] = {
+ {28, 1},
+};
+static arc arcs_63_1[3] = {
+ {156, 2},
+ {29, 3},
+ {0, 1},
+};
+static arc arcs_63_2[1] = {
+ {0, 2},
+};
+static arc arcs_63_3[2] = {
+ {28, 4},
+ {0, 3},
+};
+static arc arcs_63_4[2] = {
+ {29, 3},
+ {0, 4},
+};
+static state states_63[5] = {
+ {1, arcs_63_0},
+ {3, arcs_63_1},
+ {1, arcs_63_2},
+ {2, arcs_63_3},
+ {2, arcs_63_4},
+};
+static arc arcs_64_0[1] = {
+ {28, 1},
+};
+static arc arcs_64_1[3] = {
+ {157, 2},
+ {29, 3},
+ {0, 1},
+};
+static arc arcs_64_2[1] = {
+ {0, 2},
+};
+static arc arcs_64_3[2] = {
+ {28, 4},
+ {0, 3},
+};
+static arc arcs_64_4[2] = {
+ {29, 3},
+ {0, 4},
+};
+static state states_64[5] = {
+ {1, arcs_64_0},
+ {3, arcs_64_1},
+ {1, arcs_64_2},
+ {2, arcs_64_3},
+ {2, arcs_64_4},
+};
+static arc arcs_65_0[1] = {
+ {109, 1},
+};
+static arc arcs_65_1[2] = {
+ {25, 2},
+ {23, 3},
+};
+static arc arcs_65_2[1] = {
+ {23, 3},
+};
+static arc arcs_65_3[1] = {
+ {28, 4},
+};
+static arc arcs_65_4[1] = {
+ {0, 4},
+};
+static state states_65[5] = {
+ {1, arcs_65_0},
+ {2, arcs_65_1},
+ {1, arcs_65_2},
+ {1, arcs_65_3},
+ {1, arcs_65_4},
+};
+static arc arcs_66_0[3] = {
+ {13, 1},
+ {146, 2},
+ {77, 3},
+};
+static arc arcs_66_1[2] = {
+ {14, 4},
+ {15, 5},
+};
+static arc arcs_66_2[1] = {
+ {158, 6},
+};
+static arc arcs_66_3[1] = {
+ {21, 5},
+};
+static arc arcs_66_4[1] = {
+ {15, 5},
+};
+static arc arcs_66_5[1] = {
+ {0, 5},
+};
+static arc arcs_66_6[1] = {
+ {148, 5},
+};
+static state states_66[7] = {
+ {3, arcs_66_0},
+ {2, arcs_66_1},
+ {1, arcs_66_2},
+ {1, arcs_66_3},
+ {1, arcs_66_4},
+ {1, arcs_66_5},
+ {1, arcs_66_6},
+};
+static arc arcs_67_0[1] = {
+ {159, 1},
+};
+static arc arcs_67_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_67_2[2] = {
+ {159, 1},
+ {0, 2},
+};
+static state states_67[3] = {
+ {1, arcs_67_0},
+ {2, arcs_67_1},
+ {2, arcs_67_2},
+};
+static arc arcs_68_0[3] = {
+ {77, 1},
+ {28, 2},
+ {23, 3},
+};
+static arc arcs_68_1[1] = {
+ {77, 4},
+};
+static arc arcs_68_2[2] = {
+ {23, 3},
+ {0, 2},
+};
+static arc arcs_68_3[3] = {
+ {28, 5},
+ {160, 6},
+ {0, 3},
+};
+static arc arcs_68_4[1] = {
+ {77, 6},
+};
+static arc arcs_68_5[2] = {
+ {160, 6},
+ {0, 5},
+};
+static arc arcs_68_6[1] = {
+ {0, 6},
+};
+static state states_68[7] = {
+ {3, arcs_68_0},
+ {1, arcs_68_1},
+ {2, arcs_68_2},
+ {3, arcs_68_3},
+ {1, arcs_68_4},
+ {2, arcs_68_5},
+ {1, arcs_68_6},
+};
+static arc arcs_69_0[1] = {
+ {23, 1},
+};
+static arc arcs_69_1[2] = {
+ {28, 2},
+ {0, 1},
+};
+static arc arcs_69_2[1] = {
+ {0, 2},
+};
+static state states_69[3] = {
+ {1, arcs_69_0},
+ {2, arcs_69_1},
+ {1, arcs_69_2},
+};
+static arc arcs_70_0[1] = {
+ {84, 1},
+};
+static arc arcs_70_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_70_2[2] = {
+ {84, 1},
+ {0, 2},
+};
+static state states_70[3] = {
+ {1, arcs_70_0},
+ {2, arcs_70_1},
+ {2, arcs_70_2},
+};
+static arc arcs_71_0[1] = {
+ {28, 1},
+};
+static arc arcs_71_1[2] = {
+ {29, 2},
+ {0, 1},
+};
+static arc arcs_71_2[2] = {
+ {28, 1},
+ {0, 2},
+};
+static state states_71[3] = {
+ {1, arcs_71_0},
+ {2, arcs_71_1},
+ {2, arcs_71_2},
+};
+static arc arcs_72_0[1] = {
+ {28, 1},
+};
+static arc arcs_72_1[4] = {
+ {23, 2},
+ {157, 3},
+ {29, 4},
+ {0, 1},
+};
+static arc arcs_72_2[1] = {
+ {28, 5},
+};
+static arc arcs_72_3[1] = {
+ {0, 3},
+};
+static arc arcs_72_4[2] = {
+ {28, 6},
+ {0, 4},
+};
+static arc arcs_72_5[3] = {
+ {157, 3},
+ {29, 7},
+ {0, 5},
+};
+static arc arcs_72_6[2] = {
+ {29, 4},
+ {0, 6},
+};
+static arc arcs_72_7[2] = {
+ {28, 8},
+ {0, 7},
+};
+static arc arcs_72_8[1] = {
+ {23, 9},
+};
+static arc arcs_72_9[1] = {
+ {28, 10},
+};
+static arc arcs_72_10[2] = {
+ {29, 7},
+ {0, 10},
+};
+static state states_72[11] = {
+ {1, arcs_72_0},
+ {4, arcs_72_1},
+ {1, arcs_72_2},
+ {1, arcs_72_3},
+ {2, arcs_72_4},
+ {3, arcs_72_5},
+ {2, arcs_72_6},
+ {2, arcs_72_7},
+ {1, arcs_72_8},
+ {1, arcs_72_9},
+ {2, arcs_72_10},
+};
+static arc arcs_73_0[1] = {
+ {161, 1},
+};
+static arc arcs_73_1[1] = {
+ {21, 2},
+};
+static arc arcs_73_2[2] = {
+ {13, 3},
+ {23, 4},
+};
+static arc arcs_73_3[2] = {
+ {9, 5},
+ {15, 6},
+};
+static arc arcs_73_4[1] = {
+ {24, 7},
+};
+static arc arcs_73_5[1] = {
+ {15, 6},
+};
+static arc arcs_73_6[1] = {
+ {23, 4},
+};
+static arc arcs_73_7[1] = {
+ {0, 7},
+};
+static state states_73[8] = {
+ {1, arcs_73_0},
+ {1, arcs_73_1},
+ {2, arcs_73_2},
+ {2, arcs_73_3},
+ {1, arcs_73_4},
+ {1, arcs_73_5},
+ {1, arcs_73_6},
+ {1, arcs_73_7},
+};
+static arc arcs_74_0[3] = {
+ {162, 1},
+ {30, 2},
+ {31, 3},
+};
+static arc arcs_74_1[2] = {
+ {29, 4},
+ {0, 1},
+};
+static arc arcs_74_2[1] = {
+ {28, 5},
+};
+static arc arcs_74_3[1] = {
+ {28, 6},
+};
+static arc arcs_74_4[4] = {
+ {162, 1},
+ {30, 2},
+ {31, 3},
+ {0, 4},
+};
+static arc arcs_74_5[2] = {
+ {29, 7},
+ {0, 5},
+};
+static arc arcs_74_6[1] = {
+ {0, 6},
+};
+static arc arcs_74_7[2] = {
+ {162, 5},
+ {31, 3},
+};
+static state states_74[8] = {
+ {3, arcs_74_0},
+ {2, arcs_74_1},
+ {1, arcs_74_2},
+ {1, arcs_74_3},
+ {4, arcs_74_4},
+ {2, arcs_74_5},
+ {1, arcs_74_6},
+ {2, arcs_74_7},
+};
+static arc arcs_75_0[1] = {
+ {28, 1},
+};
+static arc arcs_75_1[3] = {
+ {157, 2},
+ {27, 3},
+ {0, 1},
+};
+static arc arcs_75_2[1] = {
+ {0, 2},
+};
+static arc arcs_75_3[1] = {
+ {28, 2},
+};
+static state states_75[4] = {
+ {1, arcs_75_0},
+ {3, arcs_75_1},
+ {1, arcs_75_2},
+ {1, arcs_75_3},
+};
+static arc arcs_76_0[2] = {
+ {156, 1},
+ {164, 1},
+};
+static arc arcs_76_1[1] = {
+ {0, 1},
+};
+static state states_76[2] = {
+ {2, arcs_76_0},
+ {1, arcs_76_1},
+};
+static arc arcs_77_0[1] = {
+ {96, 1},
+};
+static arc arcs_77_1[1] = {
+ {61, 2},
+};
+static arc arcs_77_2[1] = {
+ {85, 3},
+};
+static arc arcs_77_3[1] = {
+ {105, 4},
+};
+static arc arcs_77_4[2] = {
+ {163, 5},
+ {0, 4},
+};
+static arc arcs_77_5[1] = {
+ {0, 5},
+};
+static state states_77[6] = {
+ {1, arcs_77_0},
+ {1, arcs_77_1},
+ {1, arcs_77_2},
+ {1, arcs_77_3},
+ {2, arcs_77_4},
+ {1, arcs_77_5},
+};
+static arc arcs_78_0[1] = {
+ {92, 1},
+};
+static arc arcs_78_1[1] = {
+ {106, 2},
+};
+static arc arcs_78_2[2] = {
+ {163, 3},
+ {0, 2},
+};
+static arc arcs_78_3[1] = {
+ {0, 3},
+};
+static state states_78[4] = {
+ {1, arcs_78_0},
+ {1, arcs_78_1},
+ {2, arcs_78_2},
+ {1, arcs_78_3},
+};
+static arc arcs_79_0[2] = {
+ {157, 1},
+ {166, 1},
+};
+static arc arcs_79_1[1] = {
+ {0, 1},
+};
+static state states_79[2] = {
+ {2, arcs_79_0},
+ {1, arcs_79_1},
+};
+static arc arcs_80_0[1] = {
+ {96, 1},
+};
+static arc arcs_80_1[1] = {
+ {61, 2},
+};
+static arc arcs_80_2[1] = {
+ {85, 3},
+};
+static arc arcs_80_3[1] = {
+ {107, 4},
+};
+static arc arcs_80_4[2] = {
+ {165, 5},
+ {0, 4},
+};
+static arc arcs_80_5[1] = {
+ {0, 5},
+};
+static state states_80[6] = {
+ {1, arcs_80_0},
+ {1, arcs_80_1},
+ {1, arcs_80_2},
+ {1, arcs_80_3},
+ {2, arcs_80_4},
+ {1, arcs_80_5},
+};
+static arc arcs_81_0[1] = {
+ {92, 1},
+};
+static arc arcs_81_1[1] = {
+ {106, 2},
+};
+static arc arcs_81_2[2] = {
+ {165, 3},
+ {0, 2},
+};
+static arc arcs_81_3[1] = {
+ {0, 3},
+};
+static state states_81[4] = {
+ {1, arcs_81_0},
+ {1, arcs_81_1},
+ {2, arcs_81_2},
+ {1, arcs_81_3},
+};
+static arc arcs_82_0[1] = {
+ {28, 1},
+};
+static arc arcs_82_1[2] = {
+ {29, 0},
+ {0, 1},
+};
+static state states_82[2] = {
+ {1, arcs_82_0},
+ {2, arcs_82_1},
+};
+static arc arcs_83_0[1] = {
+ {21, 1},
+};
+static arc arcs_83_1[1] = {
+ {0, 1},
+};
+static state states_83[2] = {
+ {1, arcs_83_0},
+ {1, arcs_83_1},
+};
+static arc arcs_84_0[1] = {
+ {168, 1},
+};
+static arc arcs_84_1[2] = {
+ {9, 2},
+ {0, 1},
+};
+static arc arcs_84_2[1] = {
+ {0, 2},
+};
+static state states_84[3] = {
+ {1, arcs_84_0},
+ {2, arcs_84_1},
+ {1, arcs_84_2},
+};
+static dfa dfas[85] = {
+ {256, "single_input", 0, 3, states_0,
+ "\004\050\060\000\000\000\000\124\360\024\114\220\023\040\010\000\200\041\044\015\002\001"},
+ {257, "file_input", 0, 2, states_1,
+ "\204\050\060\000\000\000\000\124\360\024\114\220\023\040\010\000\200\041\044\015\002\001"},
+ {258, "eval_input", 0, 3, states_2,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {259, "decorator", 0, 7, states_3,
+ "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {260, "decorators", 0, 2, states_4,
+ "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {261, "decorated", 0, 3, states_5,
+ "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {262, "funcdef", 0, 6, states_6,
+ "\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {263, "parameters", 0, 4, states_7,
+ "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {264, "varargslist", 0, 10, states_8,
+ "\000\040\040\300\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {265, "fpdef", 0, 4, states_9,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {266, "fplist", 0, 3, states_10,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {267, "stmt", 0, 2, states_11,
+ "\000\050\060\000\000\000\000\124\360\024\114\220\023\040\010\000\200\041\044\015\002\001"},
+ {268, "simple_stmt", 0, 4, states_12,
+ "\000\040\040\000\000\000\000\124\360\024\114\000\000\040\010\000\200\041\044\015\000\001"},
+ {269, "small_stmt", 0, 2, states_13,
+ "\000\040\040\000\000\000\000\124\360\024\114\000\000\040\010\000\200\041\044\015\000\001"},
+ {270, "expr_stmt", 0, 6, states_14,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {271, "augassign", 0, 2, states_15,
+ "\000\000\000\000\000\300\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {272, "print_stmt", 0, 9, states_16,
+ "\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {273, "del_stmt", 0, 3, states_17,
+ "\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {274, "pass_stmt", 0, 2, states_18,
+ "\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {275, "flow_stmt", 0, 2, states_19,
+ "\000\000\000\000\000\000\000\000\360\000\000\000\000\000\000\000\000\000\000\000\000\001"},
+ {276, "break_stmt", 0, 2, states_20,
+ "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {277, "continue_stmt", 0, 2, states_21,
+ "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {278, "return_stmt", 0, 3, states_22,
+ "\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {279, "yield_stmt", 0, 2, states_23,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"},
+ {280, "raise_stmt", 0, 7, states_24,
+ "\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {281, "import_stmt", 0, 2, states_25,
+ "\000\000\000\000\000\000\000\000\000\024\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {282, "import_name", 0, 3, states_26,
+ "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {283, "import_from", 0, 8, states_27,
+ "\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {284, "import_as_name", 0, 4, states_28,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {285, "dotted_as_name", 0, 4, states_29,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {286, "import_as_names", 0, 3, states_30,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {287, "dotted_as_names", 0, 2, states_31,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {288, "dotted_name", 0, 2, states_32,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {289, "global_stmt", 0, 3, states_33,
+ "\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"},
+ {290, "exec_stmt", 0, 7, states_34,
+ "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000"},
+ {291, "assert_stmt", 0, 5, states_35,
+ "\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000"},
+ {292, "compound_stmt", 0, 2, states_36,
+ "\000\010\020\000\000\000\000\000\000\000\000\220\023\000\000\000\000\000\000\000\002\000"},
+ {293, "if_stmt", 0, 8, states_37,
+ "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"},
+ {294, "while_stmt", 0, 8, states_38,
+ "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000"},
+ {295, "for_stmt", 0, 10, states_39,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000"},
+ {296, "try_stmt", 0, 13, states_40,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"},
+ {297, "with_stmt", 0, 5, states_41,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"},
+ {298, "with_item", 0, 4, states_42,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {299, "except_clause", 0, 5, states_43,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"},
+ {300, "suite", 0, 5, states_44,
+ "\004\040\040\000\000\000\000\124\360\024\114\000\000\040\010\000\200\041\044\015\000\001"},
+ {301, "testlist_safe", 0, 5, states_45,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {302, "old_test", 0, 2, states_46,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {303, "old_lambdef", 0, 5, states_47,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"},
+ {304, "test", 0, 6, states_48,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {305, "or_test", 0, 2, states_49,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\010\000\200\041\044\015\000\000"},
+ {306, "and_test", 0, 2, states_50,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\010\000\200\041\044\015\000\000"},
+ {307, "not_test", 0, 3, states_51,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\010\000\200\041\044\015\000\000"},
+ {308, "comparison", 0, 2, states_52,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {309, "comp_op", 0, 4, states_53,
+ "\000\000\000\000\000\000\000\000\000\000\040\000\000\000\310\077\000\000\000\000\000\000"},
+ {310, "expr", 0, 2, states_54,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {311, "xor_expr", 0, 2, states_55,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {312, "and_expr", 0, 2, states_56,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {313, "shift_expr", 0, 2, states_57,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {314, "arith_expr", 0, 2, states_58,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {315, "term", 0, 2, states_59,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {316, "factor", 0, 3, states_60,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {317, "power", 0, 4, states_61,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\044\015\000\000"},
+ {318, "atom", 0, 11, states_62,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\044\015\000\000"},
+ {319, "listmaker", 0, 5, states_63,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {320, "testlist_comp", 0, 5, states_64,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {321, "lambdef", 0, 5, states_65,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"},
+ {322, "trailer", 0, 7, states_66,
+ "\000\040\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\004\000\000\000"},
+ {323, "subscriptlist", 0, 3, states_67,
+ "\000\040\240\000\000\000\000\000\000\040\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {324, "subscript", 0, 7, states_68,
+ "\000\040\240\000\000\000\000\000\000\040\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {325, "sliceop", 0, 3, states_69,
+ "\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {326, "exprlist", 0, 3, states_70,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\000\000\000\200\041\044\015\000\000"},
+ {327, "testlist", 0, 3, states_71,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {328, "dictorsetmaker", 0, 11, states_72,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {329, "classdef", 0, 8, states_73,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000"},
+ {330, "arglist", 0, 8, states_74,
+ "\000\040\040\300\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {331, "argument", 0, 4, states_75,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {332, "list_iter", 0, 2, states_76,
+ "\000\000\000\000\000\000\000\000\000\000\000\020\001\000\000\000\000\000\000\000\000\000"},
+ {333, "list_for", 0, 6, states_77,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000"},
+ {334, "list_if", 0, 4, states_78,
+ "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"},
+ {335, "comp_iter", 0, 2, states_79,
+ "\000\000\000\000\000\000\000\000\000\000\000\020\001\000\000\000\000\000\000\000\000\000"},
+ {336, "comp_for", 0, 6, states_80,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000"},
+ {337, "comp_if", 0, 4, states_81,
+ "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"},
+ {338, "testlist1", 0, 2, states_82,
+ "\000\040\040\000\000\000\000\000\000\000\000\000\000\040\010\000\200\041\044\015\000\000"},
+ {339, "encoding_decl", 0, 2, states_83,
+ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+ {340, "yield_expr", 0, 3, states_84,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"},
+};
+static label labels[169] = {
+ {0, "EMPTY"},
+ {256, 0},
+ {4, 0},
+ {268, 0},
+ {292, 0},
+ {257, 0},
+ {267, 0},
+ {0, 0},
+ {258, 0},
+ {327, 0},
+ {259, 0},
+ {50, 0},
+ {288, 0},
+ {7, 0},
+ {330, 0},
+ {8, 0},
+ {260, 0},
+ {261, 0},
+ {329, 0},
+ {262, 0},
+ {1, "def"},
+ {1, 0},
+ {263, 0},
+ {11, 0},
+ {300, 0},
+ {264, 0},
+ {265, 0},
+ {22, 0},
+ {304, 0},
+ {12, 0},
+ {16, 0},
+ {36, 0},
+ {266, 0},
+ {269, 0},
+ {13, 0},
+ {270, 0},
+ {272, 0},
+ {273, 0},
+ {274, 0},
+ {275, 0},
+ {281, 0},
+ {289, 0},
+ {290, 0},
+ {291, 0},
+ {271, 0},
+ {340, 0},
+ {37, 0},
+ {38, 0},
+ {39, 0},
+ {40, 0},
+ {41, 0},
+ {42, 0},
+ {43, 0},
+ {44, 0},
+ {45, 0},
+ {46, 0},
+ {47, 0},
+ {49, 0},
+ {1, "print"},
+ {35, 0},
+ {1, "del"},
+ {326, 0},
+ {1, "pass"},
+ {276, 0},
+ {277, 0},
+ {278, 0},
+ {280, 0},
+ {279, 0},
+ {1, "break"},
+ {1, "continue"},
+ {1, "return"},
+ {1, "raise"},
+ {282, 0},
+ {283, 0},
+ {1, "import"},
+ {287, 0},
+ {1, "from"},
+ {23, 0},
+ {286, 0},
+ {284, 0},
+ {1, "as"},
+ {285, 0},
+ {1, "global"},
+ {1, "exec"},
+ {310, 0},
+ {1, "in"},
+ {1, "assert"},
+ {293, 0},
+ {294, 0},
+ {295, 0},
+ {296, 0},
+ {297, 0},
+ {1, "if"},
+ {1, "elif"},
+ {1, "else"},
+ {1, "while"},
+ {1, "for"},
+ {1, "try"},
+ {299, 0},
+ {1, "finally"},
+ {1, "with"},
+ {298, 0},
+ {1, "except"},
+ {5, 0},
+ {6, 0},
+ {301, 0},
+ {302, 0},
+ {305, 0},
+ {303, 0},
+ {1, "lambda"},
+ {321, 0},
+ {306, 0},
+ {1, "or"},
+ {307, 0},
+ {1, "and"},
+ {1, "not"},
+ {308, 0},
+ {309, 0},
+ {20, 0},
+ {21, 0},
+ {28, 0},
+ {31, 0},
+ {30, 0},
+ {29, 0},
+ {29, 0},
+ {1, "is"},
+ {311, 0},
+ {18, 0},
+ {312, 0},
+ {33, 0},
+ {313, 0},
+ {19, 0},
+ {314, 0},
+ {34, 0},
+ {315, 0},
+ {14, 0},
+ {15, 0},
+ {316, 0},
+ {17, 0},
+ {24, 0},
+ {48, 0},
+ {32, 0},
+ {317, 0},
+ {318, 0},
+ {322, 0},
+ {320, 0},
+ {9, 0},
+ {319, 0},
+ {10, 0},
+ {26, 0},
+ {328, 0},
+ {27, 0},
+ {25, 0},
+ {338, 0},
+ {2, 0},
+ {3, 0},
+ {333, 0},
+ {336, 0},
+ {323, 0},
+ {324, 0},
+ {325, 0},
+ {1, "class"},
+ {331, 0},
+ {332, 0},
+ {334, 0},
+ {335, 0},
+ {337, 0},
+ {339, 0},
+ {1, "yield"},
+};
+grammar _PyParser_Grammar = {
+ 85,
+ dfas,
+ {169, labels},
+ 256
+};
diff --git a/contrib/tools/python/src/Python/import.c b/contrib/tools/python/src/Python/import.c
new file mode 100644
index 0000000000..dbf89b763f
--- /dev/null
+++ b/contrib/tools/python/src/Python/import.c
@@ -0,0 +1,3533 @@
+
+/* Module definition and import implementation */
+
+#include "Python.h"
+
+#include "Python-ast.h"
+#undef Yield /* undefine macro conflicting with winbase.h */
+#include "pyarena.h"
+#include "pythonrun.h"
+#include "errcode.h"
+#include "marshal.h"
+#include "code.h"
+#include "compile.h"
+#include "eval.h"
+#include "osdefs.h"
+#include "importdl.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MS_WINDOWS
+/* for stat.st_mode */
+typedef unsigned short mode_t;
+#endif
+
+
+/* Magic word to reject .pyc files generated by other Python versions.
+ It should change for each incompatible change to the bytecode.
+
+ The value of CR and LF is incorporated so if you ever read or write
+ a .pyc file in text mode the magic number will be wrong; also, the
+ Apple MPW compiler swaps their values, botching string constants.
+
+ The magic numbers must be spaced apart atleast 2 values, as the
+ -U interpeter flag will cause MAGIC+1 being used. They have been
+ odd numbers for some time now.
+
+ There were a variety of old schemes for setting the magic number.
+ The current working scheme is to increment the previous value by
+ 10.
+
+ Known values:
+ Python 1.5: 20121
+ Python 1.5.1: 20121
+ Python 1.5.2: 20121
+ Python 1.6: 50428
+ Python 2.0: 50823
+ Python 2.0.1: 50823
+ Python 2.1: 60202
+ Python 2.1.1: 60202
+ Python 2.1.2: 60202
+ Python 2.2: 60717
+ Python 2.3a0: 62011
+ Python 2.3a0: 62021
+ Python 2.3a0: 62011 (!)
+ Python 2.4a0: 62041
+ Python 2.4a3: 62051
+ Python 2.4b1: 62061
+ Python 2.5a0: 62071
+ Python 2.5a0: 62081 (ast-branch)
+ Python 2.5a0: 62091 (with)
+ Python 2.5a0: 62092 (changed WITH_CLEANUP opcode)
+ Python 2.5b3: 62101 (fix wrong code: for x, in ...)
+ Python 2.5b3: 62111 (fix wrong code: x += yield)
+ Python 2.5c1: 62121 (fix wrong lnotab with for loops and
+ storing constants that should have been removed)
+ Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp)
+ Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode)
+ Python 2.6a1: 62161 (WITH_CLEANUP optimization)
+ Python 2.7a0: 62171 (optimize list comprehensions/change LIST_APPEND)
+ Python 2.7a0: 62181 (optimize conditional branches:
+ introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
+ Python 2.7a0 62191 (introduce SETUP_WITH)
+ Python 2.7a0 62201 (introduce BUILD_SET)
+ Python 2.7a0 62211 (introduce MAP_ADD and SET_ADD)
+.
+*/
+#define MAGIC (62211 | ((long)'\r'<<16) | ((long)'\n'<<24))
+
+/* Magic word as global; note that _PyImport_Init() can change the
+ value of this global to accommodate for alterations of how the
+ compiler works which are enabled by command line switches. */
+static long pyc_magic = MAGIC;
+
+/* See _PyImport_FixupExtension() below */
+static PyObject *extensions = NULL;
+
+/* This table is defined in config.c: */
+extern struct _inittab _PyImport_Inittab[];
+
+struct _inittab *PyImport_Inittab = _PyImport_Inittab;
+
+/* these tables define the module suffixes that Python recognizes */
+struct filedescr * _PyImport_Filetab = NULL;
+
+#ifdef RISCOS
+static const struct filedescr _PyImport_StandardFiletab[] = {
+ {"/py", "U", PY_SOURCE},
+ {"/pyc", "rb", PY_COMPILED},
+ {0, 0}
+};
+#else
+static const struct filedescr _PyImport_StandardFiletab[] = {
+ {".py", "U", PY_SOURCE},
+#ifdef MS_WINDOWS
+ {".pyw", "U", PY_SOURCE},
+#endif
+ {".pyc", "rb", PY_COMPILED},
+ {0, 0}
+};
+#endif
+
+#ifdef MS_WINDOWS
+static int isdir(char *path) {
+ DWORD rv;
+ /* see issue1293 and issue3677:
+ * stat() on Windows doesn't recognise paths like
+ * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs.
+ * Also reference issue6727:
+ * stat() on Windows is broken and doesn't resolve symlinks properly.
+ */
+ rv = GetFileAttributesA(path);
+ return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY;
+}
+#else
+#ifdef HAVE_STAT
+static int isdir(char *path) {
+ struct stat statbuf;
+ return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
+}
+#else
+#ifdef RISCOS
+/* with RISCOS, isdir is in unixstuff */
+#else
+int isdir(char *path) {
+ return 0;
+}
+#endif /* RISCOS */
+#endif /* HAVE_STAT */
+#endif /* MS_WINDOWS */
+
+/* Initialize things */
+
+void
+_PyImport_Init(void)
+{
+ const struct filedescr *scan;
+ struct filedescr *filetab;
+ int countD = 0;
+ int countS = 0;
+
+ /* prepare _PyImport_Filetab: copy entries from
+ _PyImport_DynLoadFiletab and _PyImport_StandardFiletab.
+ */
+#ifdef HAVE_DYNAMIC_LOADING
+ for (scan = _PyImport_DynLoadFiletab; scan->suffix != NULL; ++scan)
+ ++countD;
+#endif
+ for (scan = _PyImport_StandardFiletab; scan->suffix != NULL; ++scan)
+ ++countS;
+ filetab = PyMem_NEW(struct filedescr, countD + countS + 1);
+ if (filetab == NULL)
+ Py_FatalError("Can't initialize import file table.");
+#ifdef HAVE_DYNAMIC_LOADING
+ memcpy(filetab, _PyImport_DynLoadFiletab,
+ countD * sizeof(struct filedescr));
+#endif
+ memcpy(filetab + countD, _PyImport_StandardFiletab,
+ countS * sizeof(struct filedescr));
+ filetab[countD + countS].suffix = NULL;
+
+ _PyImport_Filetab = filetab;
+
+ if (Py_OptimizeFlag) {
+ /* Replace ".pyc" with ".pyo" in _PyImport_Filetab */
+ for (; filetab->suffix != NULL; filetab++) {
+#ifndef RISCOS
+ if (strcmp(filetab->suffix, ".pyc") == 0)
+ filetab->suffix = ".pyo";
+#else
+ if (strcmp(filetab->suffix, "/pyc") == 0)
+ filetab->suffix = "/pyo";
+#endif
+ }
+ }
+
+ if (Py_UnicodeFlag) {
+ /* Fix the pyc_magic so that byte compiled code created
+ using the all-Unicode method doesn't interfere with
+ code created in normal operation mode. */
+ pyc_magic = MAGIC + 1;
+ }
+}
+
+void
+_PyImportHooks_Init(void)
+{
+ PyObject *v, *path_hooks = NULL, *zimpimport;
+ int err = 0;
+
+ /* adding sys.path_hooks and sys.path_importer_cache, setting up
+ zipimport */
+ if (PyType_Ready(&PyNullImporter_Type) < 0)
+ goto error;
+
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# installing zipimport hook\n");
+
+ v = PyList_New(0);
+ if (v == NULL)
+ goto error;
+ err = PySys_SetObject("meta_path", v);
+ Py_DECREF(v);
+ if (err)
+ goto error;
+ v = PyDict_New();
+ if (v == NULL)
+ goto error;
+ err = PySys_SetObject("path_importer_cache", v);
+ Py_DECREF(v);
+ if (err)
+ goto error;
+ path_hooks = PyList_New(0);
+ if (path_hooks == NULL)
+ goto error;
+ err = PySys_SetObject("path_hooks", path_hooks);
+ if (err) {
+ error:
+ PyErr_Print();
+ Py_FatalError("initializing sys.meta_path, sys.path_hooks, "
+ "path_importer_cache, or NullImporter failed"
+ );
+ }
+
+ zimpimport = PyImport_ImportModule("zipimport");
+ if (zimpimport == NULL) {
+ PyErr_Clear(); /* No zip import module -- okay */
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# can't import zipimport\n");
+ }
+ else {
+ PyObject *zipimporter = PyObject_GetAttrString(zimpimport,
+ "zipimporter");
+ Py_DECREF(zimpimport);
+ if (zipimporter == NULL) {
+ PyErr_Clear(); /* No zipimporter object -- okay */
+ if (Py_VerboseFlag)
+ PySys_WriteStderr(
+ "# can't import zipimport.zipimporter\n");
+ }
+ else {
+ /* sys.path_hooks.append(zipimporter) */
+ err = PyList_Append(path_hooks, zipimporter);
+ Py_DECREF(zipimporter);
+ if (err)
+ goto error;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr(
+ "# installed zipimport hook\n");
+ }
+ }
+ Py_DECREF(path_hooks);
+}
+
+void
+_PyImport_Fini(void)
+{
+ Py_XDECREF(extensions);
+ extensions = NULL;
+ PyMem_DEL(_PyImport_Filetab);
+ _PyImport_Filetab = NULL;
+}
+
+
+/* Locking primitives to prevent parallel imports of the same module
+ in different threads to return with a partially loaded module.
+ These calls are serialized by the global interpreter lock. */
+
+#ifdef WITH_THREAD
+
+#include "pythread.h"
+
+static PyThread_type_lock import_lock = 0;
+static long import_lock_thread = -1;
+static int import_lock_level = 0;
+
+void
+_PyImport_AcquireLock(void)
+{
+ long me = PyThread_get_thread_ident();
+ if (me == -1)
+ return; /* Too bad */
+ if (import_lock == NULL) {
+ import_lock = PyThread_allocate_lock();
+ if (import_lock == NULL)
+ return; /* Nothing much we can do. */
+ }
+ if (import_lock_thread == me) {
+ import_lock_level++;
+ return;
+ }
+ if (import_lock_thread != -1 || !PyThread_acquire_lock(import_lock, 0))
+ {
+ PyThreadState *tstate = PyEval_SaveThread();
+ PyThread_acquire_lock(import_lock, 1);
+ PyEval_RestoreThread(tstate);
+ }
+ import_lock_thread = me;
+ import_lock_level = 1;
+}
+
+int
+_PyImport_ReleaseLock(void)
+{
+ long me = PyThread_get_thread_ident();
+ if (me == -1 || import_lock == NULL)
+ return 0; /* Too bad */
+ if (import_lock_thread != me)
+ return -1;
+ import_lock_level--;
+ if (import_lock_level == 0) {
+ import_lock_thread = -1;
+ PyThread_release_lock(import_lock);
+ }
+ return 1;
+}
+
+/* This function is called from PyOS_AfterFork to ensure that newly
+ created child processes do not share locks with the parent.
+ We now acquire the import lock around fork() calls but on some platforms
+ (Solaris 9 and earlier? see isue7242) that still left us with problems. */
+
+void
+_PyImport_ReInitLock(void)
+{
+ if (import_lock != NULL) {
+ import_lock = PyThread_allocate_lock();
+ if (import_lock == NULL) {
+ Py_FatalError("PyImport_ReInitLock failed to create a new lock");
+ }
+ }
+ import_lock_thread = -1;
+ import_lock_level = 0;
+}
+
+#endif
+
+static PyObject *
+imp_lock_held(PyObject *self, PyObject *noargs)
+{
+#ifdef WITH_THREAD
+ return PyBool_FromLong(import_lock_thread != -1);
+#else
+ return PyBool_FromLong(0);
+#endif
+}
+
+static PyObject *
+imp_acquire_lock(PyObject *self, PyObject *noargs)
+{
+#ifdef WITH_THREAD
+ _PyImport_AcquireLock();
+#endif
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+imp_release_lock(PyObject *self, PyObject *noargs)
+{
+#ifdef WITH_THREAD
+ if (_PyImport_ReleaseLock() < 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "not holding the import lock");
+ return NULL;
+ }
+#endif
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static void
+imp_modules_reloading_clear(void)
+{
+ PyInterpreterState *interp = PyThreadState_Get()->interp;
+ if (interp->modules_reloading != NULL)
+ PyDict_Clear(interp->modules_reloading);
+}
+
+/* Helper for sys */
+
+PyObject *
+PyImport_GetModuleDict(void)
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ if (interp->modules == NULL)
+ Py_FatalError("PyImport_GetModuleDict: no module dictionary!");
+ return interp->modules;
+}
+
+
+/* List of names to clear in sys */
+static char* sys_deletes[] = {
+ "path", "argv", "ps1", "ps2", "exitfunc",
+ "exc_type", "exc_value", "exc_traceback",
+ "last_type", "last_value", "last_traceback",
+ "path_hooks", "path_importer_cache", "meta_path",
+ /* misc stuff */
+ "flags", "float_info",
+ NULL
+};
+
+static char* sys_files[] = {
+ "stdin", "__stdin__",
+ "stdout", "__stdout__",
+ "stderr", "__stderr__",
+ NULL
+};
+
+
+/* Un-initialize things, as good as we can */
+
+void
+PyImport_Cleanup(void)
+{
+ Py_ssize_t pos, ndone;
+ char *name;
+ PyObject *key, *value, *dict;
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ PyObject *modules = interp->modules;
+
+ if (modules == NULL)
+ return; /* Already done */
+
+ /* Delete some special variables first. These are common
+ places where user values hide and people complain when their
+ destructors fail. Since the modules containing them are
+ deleted *last* of all, they would come too late in the normal
+ destruction order. Sigh. */
+
+ value = PyDict_GetItemString(modules, "__builtin__");
+ if (value != NULL && PyModule_Check(value)) {
+ dict = PyModule_GetDict(value);
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# clear __builtin__._\n");
+ if (PyDict_SetItemString(dict, "_", Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+ value = PyDict_GetItemString(modules, "sys");
+ if (value != NULL && PyModule_Check(value)) {
+ char **p;
+ PyObject *v;
+ dict = PyModule_GetDict(value);
+ for (p = sys_deletes; *p != NULL; p++) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# clear sys.%s\n", *p);
+ if (PyDict_SetItemString(dict, *p, Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+ for (p = sys_files; *p != NULL; p+=2) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# restore sys.%s\n", *p);
+ v = PyDict_GetItemString(dict, *(p+1));
+ if (v == NULL)
+ v = Py_None;
+ if (PyDict_SetItemString(dict, *p, v) < 0) {
+ PyErr_Clear();
+ }
+ }
+ }
+
+ /* First, delete __main__ */
+ value = PyDict_GetItemString(modules, "__main__");
+ if (value != NULL && PyModule_Check(value)) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# cleanup __main__\n");
+ _PyModule_Clear(value);
+ if (PyDict_SetItemString(modules, "__main__", Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+
+ /* The special treatment of __builtin__ here is because even
+ when it's not referenced as a module, its dictionary is
+ referenced by almost every module's __builtins__. Since
+ deleting a module clears its dictionary (even if there are
+ references left to it), we need to delete the __builtin__
+ module last. Likewise, we don't delete sys until the very
+ end because it is implicitly referenced (e.g. by print).
+
+ Also note that we 'delete' modules by replacing their entry
+ in the modules dict with None, rather than really deleting
+ them; this avoids a rehash of the modules dictionary and
+ also marks them as "non existent" so they won't be
+ re-imported. */
+
+ /* Next, repeatedly delete modules with a reference count of
+ one (skipping __builtin__ and sys) and delete them */
+ do {
+ ndone = 0;
+ pos = 0;
+ while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (value->ob_refcnt != 1)
+ continue;
+ if (PyString_Check(key) && PyModule_Check(value)) {
+ name = PyString_AS_STRING(key);
+ if (strcmp(name, "__builtin__") == 0)
+ continue;
+ if (strcmp(name, "sys") == 0)
+ continue;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr(
+ "# cleanup[1] %s\n", name);
+ _PyModule_Clear(value);
+ if (PyDict_SetItem(modules, key, Py_None) < 0) {
+ PyErr_Clear();
+ }
+ ndone++;
+ }
+ }
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ }
+ } while (ndone > 0);
+
+ /* Next, delete all modules (still skipping __builtin__ and sys) */
+ pos = 0;
+ while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (PyString_Check(key) && PyModule_Check(value)) {
+ name = PyString_AS_STRING(key);
+ if (strcmp(name, "__builtin__") == 0)
+ continue;
+ if (strcmp(name, "sys") == 0)
+ continue;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# cleanup[2] %s\n", name);
+ _PyModule_Clear(value);
+ if (PyDict_SetItem(modules, key, Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ }
+ }
+
+ /* Next, delete sys and __builtin__ (in that order) */
+ value = PyDict_GetItemString(modules, "sys");
+ if (value != NULL && PyModule_Check(value)) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# cleanup sys\n");
+ _PyModule_Clear(value);
+ if (PyDict_SetItemString(modules, "sys", Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+ value = PyDict_GetItemString(modules, "__builtin__");
+ if (value != NULL && PyModule_Check(value)) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# cleanup __builtin__\n");
+ _PyModule_Clear(value);
+ if (PyDict_SetItemString(modules, "__builtin__", Py_None) < 0) {
+ PyErr_Clear();
+ }
+ }
+
+ /* Finally, clear and delete the modules directory */
+ PyDict_Clear(modules);
+ interp->modules = NULL;
+ Py_DECREF(modules);
+ Py_CLEAR(interp->modules_reloading);
+}
+
+
+/* Helper for pythonrun.c -- return magic number */
+
+long
+PyImport_GetMagicNumber(void)
+{
+ return pyc_magic;
+}
+
+
+/* Magic for extension modules (built-in as well as dynamically
+ loaded). To prevent initializing an extension module more than
+ once, we keep a static dictionary 'extensions' keyed by module name
+ (for built-in modules) or by filename (for dynamically loaded
+ modules), containing these modules. A copy of the module's
+ dictionary is stored by calling _PyImport_FixupExtension()
+ immediately after the module initialization function succeeds. A
+ copy can be retrieved from there by calling
+ _PyImport_FindExtension(). */
+
+PyObject *
+_PyImport_FixupExtension(char *name, char *filename)
+{
+ PyObject *modules, *mod, *dict, *copy;
+ if (extensions == NULL) {
+ extensions = PyDict_New();
+ if (extensions == NULL)
+ return NULL;
+ }
+ modules = PyImport_GetModuleDict();
+ mod = PyDict_GetItemString(modules, name);
+ if (mod == NULL || !PyModule_Check(mod)) {
+ PyErr_Format(PyExc_SystemError,
+ "_PyImport_FixupExtension: module %.200s not loaded", name);
+ return NULL;
+ }
+ dict = PyModule_GetDict(mod);
+ if (dict == NULL)
+ return NULL;
+ copy = PyDict_Copy(dict);
+ if (copy == NULL)
+ return NULL;
+ PyDict_SetItemString(extensions, filename, copy);
+ Py_DECREF(copy);
+ return copy;
+}
+
+PyObject *
+_PyImport_FindExtension(char *name, char *filename)
+{
+ PyObject *dict, *mod, *mdict;
+ if (extensions == NULL)
+ return NULL;
+ dict = PyDict_GetItemString(extensions, filename);
+ if (dict == NULL)
+ return NULL;
+ mod = PyImport_AddModule(name);
+ if (mod == NULL)
+ return NULL;
+ mdict = PyModule_GetDict(mod);
+ if (mdict == NULL)
+ return NULL;
+ if (PyDict_Update(mdict, dict))
+ return NULL;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # previously loaded (%s)\n",
+ name, filename);
+ return mod;
+}
+
+
+/* Get the module object corresponding to a module name.
+ First check the modules dictionary if there's one there,
+ if not, create a new one and insert it in the modules dictionary.
+ Because the former action is most common, THIS DOES NOT RETURN A
+ 'NEW' REFERENCE! */
+
+static PyObject *
+_PyImport_AddModuleObject(PyObject *name)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *m;
+
+ if ((m = _PyDict_GetItemWithError(modules, name)) != NULL &&
+ PyModule_Check(m)) {
+ return m;
+ }
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ m = PyModule_New(PyString_AS_STRING(name));
+ if (m == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItem(modules, name, m) != 0) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ assert(Py_REFCNT(m) > 1);
+ Py_DECREF(m); /* Yes, it still exists, in modules! */
+
+ return m;
+}
+
+PyObject *
+PyImport_AddModule(const char *name)
+{
+ PyObject *nameobj, *module;
+ nameobj = PyString_FromString(name);
+ if (nameobj == NULL)
+ return NULL;
+ module = _PyImport_AddModuleObject(nameobj);
+ Py_DECREF(nameobj);
+ return module;
+}
+
+/* Remove name from sys.modules, if it's there. */
+static void
+remove_module(const char *name)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ if (PyDict_GetItemString(modules, name) == NULL)
+ return;
+ if (PyDict_DelItemString(modules, name) < 0)
+ Py_FatalError("import: deleting existing key in "
+ "sys.modules failed");
+}
+
+/* Execute a code object in a module and return the module object
+ * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is
+ * removed from sys.modules, to avoid leaving damaged module objects
+ * in sys.modules. The caller may wish to restore the original
+ * module object (if any) in this case; PyImport_ReloadModule is an
+ * example.
+ */
+PyObject *
+PyImport_ExecCodeModule(char *name, PyObject *co)
+{
+ return PyImport_ExecCodeModuleEx(name, co, (char *)NULL);
+}
+
+PyObject *
+PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *m, *d, *v;
+
+ m = PyImport_AddModule(name);
+ if (m == NULL)
+ return NULL;
+ /* If the module is being reloaded, we get the old module back
+ and re-use its dict to exec the new code. */
+ d = PyModule_GetDict(m);
+ if (PyDict_GetItemString(d, "__builtins__") == NULL) {
+ if (PyDict_SetItemString(d, "__builtins__",
+ PyEval_GetBuiltins()) != 0)
+ goto error;
+ }
+ /* Remember the filename as the __file__ attribute */
+ v = NULL;
+ if (pathname != NULL) {
+ v = PyString_FromString(pathname);
+ if (v == NULL)
+ PyErr_Clear();
+ }
+ if (v == NULL) {
+ v = ((PyCodeObject *)co)->co_filename;
+ Py_INCREF(v);
+ }
+ if (PyDict_SetItemString(d, "__file__", v) != 0)
+ PyErr_Clear(); /* Not important enough to report */
+ Py_DECREF(v);
+
+ v = PyEval_EvalCode((PyCodeObject *)co, d, d);
+ if (v == NULL)
+ goto error;
+ Py_DECREF(v);
+
+ if ((m = PyDict_GetItemString(modules, name)) == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "Loaded module %.200s not found in sys.modules",
+ name);
+ return NULL;
+ }
+
+ Py_INCREF(m);
+
+ return m;
+
+ error:
+ remove_module(name);
+ return NULL;
+}
+
+
+/* Given a pathname for a Python source file, fill a buffer with the
+ pathname for the corresponding compiled file. Return the pathname
+ for the compiled file, or NULL if there's no space in the buffer.
+ Doesn't set an exception. */
+
+static char *
+make_compiled_pathname(char *pathname, char *buf, size_t buflen)
+{
+ size_t len = strlen(pathname);
+ if (len+2 > buflen)
+ return NULL;
+
+#ifdef MS_WINDOWS
+ /* Treat .pyw as if it were .py. The case of ".pyw" must match
+ that used in _PyImport_StandardFiletab. */
+ if (len >= 4 && strcmp(&pathname[len-4], ".pyw") == 0)
+ --len; /* pretend 'w' isn't there */
+#endif
+ memcpy(buf, pathname, len);
+ buf[len] = Py_OptimizeFlag ? 'o' : 'c';
+ buf[len+1] = '\0';
+
+ return buf;
+}
+
+
+/* Given a pathname for a Python source file, its time of last
+ modification, and a pathname for a compiled file, check whether the
+ compiled file represents the same version of the source. If so,
+ return a FILE pointer for the compiled file, positioned just after
+ the header; if not, return NULL.
+ Doesn't set an exception. */
+
+static FILE *
+check_compiled_module(char *pathname, time_t mtime, char *cpathname)
+{
+ FILE *fp;
+ long magic;
+ long pyc_mtime;
+
+ fp = fopen(cpathname, "rb");
+ if (fp == NULL)
+ return NULL;
+ magic = PyMarshal_ReadLongFromFile(fp);
+ if (magic != pyc_magic) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# %s has bad magic\n", cpathname);
+ fclose(fp);
+ return NULL;
+ }
+ pyc_mtime = PyMarshal_ReadLongFromFile(fp);
+ if (pyc_mtime != mtime) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# %s has bad mtime\n", cpathname);
+ fclose(fp);
+ return NULL;
+ }
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# %s matches %s\n", cpathname, pathname);
+ return fp;
+}
+
+
+/* Read a code object from a file and check it for validity */
+
+static PyCodeObject *
+read_compiled_module(char *cpathname, FILE *fp)
+{
+ PyObject *co;
+
+ co = PyMarshal_ReadLastObjectFromFile(fp);
+ if (co == NULL)
+ return NULL;
+ if (!PyCode_Check(co)) {
+ PyErr_Format(PyExc_ImportError,
+ "Non-code object in %.200s", cpathname);
+ Py_DECREF(co);
+ return NULL;
+ }
+ return (PyCodeObject *)co;
+}
+
+
+/* Load a module from a compiled file, execute it, and return its
+ module object WITH INCREMENTED REFERENCE COUNT */
+
+static PyObject *
+load_compiled_module(char *name, char *cpathname, FILE *fp)
+{
+ long magic;
+ PyCodeObject *co;
+ PyObject *m;
+
+ magic = PyMarshal_ReadLongFromFile(fp);
+ if (magic != pyc_magic) {
+ PyErr_Format(PyExc_ImportError,
+ "Bad magic number in %.200s", cpathname);
+ return NULL;
+ }
+ (void) PyMarshal_ReadLongFromFile(fp);
+ co = read_compiled_module(cpathname, fp);
+ if (co == NULL)
+ return NULL;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # precompiled from %s\n",
+ name, cpathname);
+ m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, cpathname);
+ Py_DECREF(co);
+
+ return m;
+}
+
+/* Parse a source file and return the corresponding code object */
+
+static PyCodeObject *
+parse_source_module(const char *pathname, FILE *fp)
+{
+ PyCodeObject *co = NULL;
+ mod_ty mod;
+ PyCompilerFlags flags;
+ PyArena *arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+
+ flags.cf_flags = 0;
+
+ mod = PyParser_ASTFromFile(fp, pathname, Py_file_input, 0, 0, &flags,
+ NULL, arena);
+ if (mod) {
+ co = PyAST_Compile(mod, pathname, NULL, arena);
+ }
+ PyArena_Free(arena);
+ return co;
+}
+
+
+/* Helper to open a bytecode file for writing in exclusive mode */
+
+static FILE *
+open_exclusive(char *filename, mode_t mode)
+{
+#if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
+ /* Use O_EXCL to avoid a race condition when another process tries to
+ write the same file. When that happens, our open() call fails,
+ which is just fine (since it's only a cache).
+ XXX If the file exists and is writable but the directory is not
+ writable, the file will never be written. Oh well.
+ */
+ int fd;
+ (void) unlink(filename);
+ fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC
+#ifdef O_BINARY
+ |O_BINARY /* necessary for Windows */
+#endif
+#ifdef __VMS
+ , mode, "ctxt=bin", "shr=nil"
+#else
+ , mode
+#endif
+ );
+ if (fd < 0)
+ return NULL;
+ return fdopen(fd, "wb");
+#else
+ /* Best we can do -- on Windows this can't happen anyway */
+ return fopen(filename, "wb");
+#endif
+}
+
+
+/* Write a compiled module to a file, placing the time of last
+ modification of its source into the header.
+ Errors are ignored, if a write error occurs an attempt is made to
+ remove the file. */
+
+static void
+write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, time_t mtime)
+{
+ FILE *fp;
+#ifdef MS_WINDOWS /* since Windows uses different permissions */
+ mode_t mode = srcstat->st_mode & ~S_IEXEC;
+ /* Issue #6074: We ensure user write access, so we can delete it later
+ * when the source file changes. (On POSIX, this only requires write
+ * access to the directory, on Windows, we need write access to the file
+ * as well)
+ */
+ mode |= _S_IWRITE;
+#else
+ mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
+#endif
+
+ fp = open_exclusive(cpathname, mode);
+ if (fp == NULL) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr(
+ "# can't create %s\n", cpathname);
+ return;
+ }
+ PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);
+ /* First write a 0 for mtime */
+ PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
+ PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
+ if (fflush(fp) != 0 || ferror(fp)) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# can't write %s\n", cpathname);
+ /* Don't keep partial file */
+ fclose(fp);
+ (void) unlink(cpathname);
+ return;
+ }
+ /* Now write the true mtime (as a 32-bit field) */
+ fseek(fp, 4L, 0);
+ assert(mtime <= 0xFFFFFFFF);
+ PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
+ fflush(fp);
+ fclose(fp);
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# wrote %s\n", cpathname);
+}
+
+static void
+update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname)
+{
+ PyObject *constants, *tmp;
+ Py_ssize_t i, n;
+
+ if (!_PyString_Eq(co->co_filename, oldname))
+ return;
+
+ tmp = co->co_filename;
+ co->co_filename = newname;
+ Py_INCREF(co->co_filename);
+ Py_DECREF(tmp);
+
+ constants = co->co_consts;
+ n = PyTuple_GET_SIZE(constants);
+ for (i = 0; i < n; i++) {
+ tmp = PyTuple_GET_ITEM(constants, i);
+ if (PyCode_Check(tmp))
+ update_code_filenames((PyCodeObject *)tmp,
+ oldname, newname);
+ }
+}
+
+static int
+update_compiled_module(PyCodeObject *co, char *pathname)
+{
+ PyObject *oldname, *newname;
+
+ if (strcmp(PyString_AsString(co->co_filename), pathname) == 0)
+ return 0;
+
+ newname = PyString_FromString(pathname);
+ if (newname == NULL)
+ return -1;
+
+ oldname = co->co_filename;
+ Py_INCREF(oldname);
+ update_code_filenames(co, oldname, newname);
+ Py_DECREF(oldname);
+ Py_DECREF(newname);
+ return 1;
+}
+
+#ifdef MS_WINDOWS
+
+/* Seconds between 1.1.1601 and 1.1.1970 */
+static __int64 secs_between_epochs = 11644473600;
+
+/* Get mtime from file pointer. */
+
+static time_t
+win32_mtime(FILE *fp, char *pathname)
+{
+ __int64 filetime;
+ HANDLE fh;
+ BY_HANDLE_FILE_INFORMATION file_information;
+
+ fh = (HANDLE)_get_osfhandle(fileno(fp));
+ if (fh == INVALID_HANDLE_VALUE ||
+ !GetFileInformationByHandle(fh, &file_information)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "unable to get file status from '%s'",
+ pathname);
+ return -1;
+ }
+ /* filetime represents the number of 100ns intervals since
+ 1.1.1601 (UTC). Convert to seconds since 1.1.1970 (UTC). */
+ filetime = (__int64)file_information.ftLastWriteTime.dwHighDateTime << 32 |
+ file_information.ftLastWriteTime.dwLowDateTime;
+ return filetime / 10000000 - secs_between_epochs;
+}
+
+#endif /* #ifdef MS_WINDOWS */
+
+
+/* Load a source module from a given file and return its module
+ object WITH INCREMENTED REFERENCE COUNT. If there's a matching
+ byte-compiled file, use that instead. */
+
+static PyObject *
+load_source_module(char *name, char *pathname, FILE *fp)
+{
+ struct stat st;
+ FILE *fpc;
+ char *buf;
+ char *cpathname;
+ PyCodeObject *co = NULL;
+ PyObject *m;
+ time_t mtime;
+
+ if (fstat(fileno(fp), &st) != 0) {
+ PyErr_Format(PyExc_RuntimeError,
+ "unable to get file status from '%s'",
+ pathname);
+ return NULL;
+ }
+
+#ifdef MS_WINDOWS
+ mtime = win32_mtime(fp, pathname);
+ if (mtime == (time_t)-1 && PyErr_Occurred())
+ return NULL;
+#else
+ mtime = st.st_mtime;
+#endif
+ if (sizeof mtime > 4) {
+ /* Python's .pyc timestamp handling presumes that the timestamp fits
+ in 4 bytes. Since the code only does an equality comparison,
+ ordering is not important and we can safely ignore the higher bits
+ (collisions are extremely unlikely).
+ */
+ mtime &= 0xFFFFFFFF;
+ }
+ buf = PyMem_MALLOC(MAXPATHLEN+1);
+ if (buf == NULL) {
+ return PyErr_NoMemory();
+ }
+ cpathname = make_compiled_pathname(pathname, buf,
+ (size_t)MAXPATHLEN + 1);
+ if (cpathname != NULL &&
+ (fpc = check_compiled_module(pathname, mtime, cpathname))) {
+ co = read_compiled_module(cpathname, fpc);
+ fclose(fpc);
+ if (co == NULL)
+ goto error_exit;
+ if (update_compiled_module(co, pathname) < 0)
+ goto error_exit;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # precompiled from %s\n",
+ name, cpathname);
+ pathname = cpathname;
+ }
+ else {
+ co = parse_source_module(pathname, fp);
+ if (co == NULL)
+ goto error_exit;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # from %s\n",
+ name, pathname);
+ if (cpathname) {
+ PyObject *ro = PySys_GetObject("dont_write_bytecode");
+ int b = (ro == NULL) ? 0 : PyObject_IsTrue(ro);
+ if (b < 0)
+ goto error_exit;
+ if (!b)
+ write_compiled_module(co, cpathname, &st, mtime);
+ }
+ }
+ m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname);
+ Py_DECREF(co);
+
+ PyMem_FREE(buf);
+ return m;
+
+error_exit:
+ Py_XDECREF(co);
+ PyMem_FREE(buf);
+ return NULL;
+}
+
+
+/* Forward */
+static PyObject *load_module(char *, FILE *, char *, int, PyObject *);
+static struct filedescr *find_module(char *, char *, PyObject *,
+ char *, size_t, FILE **, PyObject **);
+static struct _frozen *find_frozen(char *name);
+
+/* Load a package and return its module object WITH INCREMENTED
+ REFERENCE COUNT */
+
+static PyObject *
+load_package(char *name, char *pathname)
+{
+ PyObject *m, *d;
+ PyObject *file = NULL;
+ PyObject *path = NULL;
+ int err;
+ char *buf = NULL;
+ FILE *fp = NULL;
+ struct filedescr *fdp;
+
+ m = PyImport_AddModule(name);
+ if (m == NULL)
+ return NULL;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # directory %s\n",
+ name, pathname);
+ d = PyModule_GetDict(m);
+ file = PyString_FromString(pathname);
+ if (file == NULL)
+ goto error;
+ path = Py_BuildValue("[O]", file);
+ if (path == NULL)
+ goto error;
+ err = PyDict_SetItemString(d, "__file__", file);
+ if (err == 0)
+ err = PyDict_SetItemString(d, "__path__", path);
+ if (err != 0)
+ goto error;
+ buf = PyMem_MALLOC(MAXPATHLEN+1);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ buf[0] = '\0';
+ fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL);
+ if (fdp == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_ImportError)) {
+ PyErr_Clear();
+ Py_INCREF(m);
+ }
+ else
+ m = NULL;
+ goto cleanup;
+ }
+ m = load_module(name, fp, buf, fdp->type, NULL);
+ if (fp != NULL)
+ fclose(fp);
+ goto cleanup;
+
+ error:
+ m = NULL;
+ cleanup:
+ if (buf)
+ PyMem_FREE(buf);
+ Py_XDECREF(path);
+ Py_XDECREF(file);
+ return m;
+}
+
+
+/* Helper to test for built-in module */
+
+static int
+is_builtin(char *name)
+{
+ int i;
+ for (i = 0; PyImport_Inittab[i].name != NULL; i++) {
+ if (strcmp(name, PyImport_Inittab[i].name) == 0) {
+ if (PyImport_Inittab[i].initfunc == NULL)
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* Return an importer object for a sys.path/pkg.__path__ item 'p',
+ possibly by fetching it from the path_importer_cache dict. If it
+ wasn't yet cached, traverse path_hooks until a hook is found
+ that can handle the path item. Return None if no hook could;
+ this tells our caller it should fall back to the builtin
+ import mechanism. Cache the result in path_importer_cache.
+ Returns a borrowed reference. */
+
+static PyObject *
+get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks,
+ PyObject *p)
+{
+ PyObject *importer;
+ Py_ssize_t j, nhooks;
+
+ /* These conditions are the caller's responsibility: */
+ assert(PyList_Check(path_hooks));
+ assert(PyDict_Check(path_importer_cache));
+
+ nhooks = PyList_Size(path_hooks);
+ if (nhooks < 0)
+ return NULL; /* Shouldn't happen */
+
+ importer = PyDict_GetItem(path_importer_cache, p);
+ if (importer != NULL)
+ return importer;
+
+ /* set path_importer_cache[p] to None to avoid recursion */
+ if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0)
+ return NULL;
+
+ for (j = 0; j < nhooks; j++) {
+ PyObject *hook = PyList_GetItem(path_hooks, j);
+ if (hook == NULL)
+ return NULL;
+ importer = PyObject_CallFunctionObjArgs(hook, p, NULL);
+ if (importer != NULL)
+ break;
+
+ if (!PyErr_ExceptionMatches(PyExc_ImportError)) {
+ return NULL;
+ }
+ PyErr_Clear();
+ }
+ if (importer == NULL) {
+ importer = PyObject_CallFunctionObjArgs(
+ (PyObject *)&PyNullImporter_Type, p, NULL
+ );
+ if (importer == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_ImportError)) {
+ PyErr_Clear();
+ return Py_None;
+ }
+ }
+ }
+ if (importer != NULL) {
+ int err = PyDict_SetItem(path_importer_cache, p, importer);
+ Py_DECREF(importer);
+ if (err != 0)
+ return NULL;
+ }
+ return importer;
+}
+
+PyAPI_FUNC(PyObject *)
+PyImport_GetImporter(PyObject *path) {
+ PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL;
+
+ if ((path_importer_cache = PySys_GetObject("path_importer_cache"))) {
+ if ((path_hooks = PySys_GetObject("path_hooks"))) {
+ importer = get_path_importer(path_importer_cache,
+ path_hooks, path);
+ }
+ }
+ Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */
+ return importer;
+}
+
+/* Search the path (default sys.path) for a module. Return the
+ corresponding filedescr struct, and (via return arguments) the
+ pathname and an open file. Return NULL if the module is not found. */
+
+#ifdef MS_COREDLL
+extern FILE *PyWin_FindRegisteredModule(const char *, struct filedescr **,
+ char *, Py_ssize_t);
+#endif
+
+static int case_ok(char *, Py_ssize_t, Py_ssize_t, char *);
+static int find_init_module(char *); /* Forward */
+static struct filedescr importhookdescr = {"", "", IMP_HOOK};
+
+static struct filedescr *
+find_module(char *fullname, char *subname, PyObject *path, char *buf,
+ size_t buflen, FILE **p_fp, PyObject **p_loader)
+{
+ Py_ssize_t i, npath;
+ size_t len, namelen;
+ struct filedescr *fdp = NULL;
+ char *filemode;
+ FILE *fp = NULL;
+ PyObject *path_hooks, *path_importer_cache;
+ static struct filedescr fd_frozen = {"", "", PY_FROZEN};
+ static struct filedescr fd_builtin = {"", "", C_BUILTIN};
+ static struct filedescr fd_package = {"", "", PKG_DIRECTORY};
+ char *name;
+#if defined(PYOS_OS2)
+ size_t saved_len;
+ size_t saved_namelen;
+ char *saved_buf = NULL;
+#endif
+ if (p_loader != NULL)
+ *p_loader = NULL;
+
+ if (strlen(subname) > MAXPATHLEN) {
+ PyErr_SetString(PyExc_OverflowError,
+ "module name is too long");
+ return NULL;
+ }
+ name = PyMem_MALLOC(MAXPATHLEN+1);
+ if (name == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ strcpy(name, subname);
+
+ /* sys.meta_path import hook */
+ if (p_loader != NULL) {
+ PyObject *meta_path;
+
+ meta_path = PySys_GetObject("meta_path");
+ if (meta_path == NULL || !PyList_Check(meta_path)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "sys.meta_path must be a list of "
+ "import hooks");
+ goto error_exit;
+ }
+ Py_INCREF(meta_path); /* zap guard */
+ npath = PyList_Size(meta_path);
+ for (i = 0; i < npath; i++) {
+ PyObject *loader;
+ PyObject *hook = PyList_GetItem(meta_path, i);
+ loader = PyObject_CallMethod(hook, "find_module",
+ "sO", fullname,
+ path != NULL ?
+ path : Py_None);
+ if (loader == NULL) {
+ Py_DECREF(meta_path);
+ goto error_exit; /* true error */
+ }
+ if (loader != Py_None) {
+ /* a loader was found */
+ *p_loader = loader;
+ Py_DECREF(meta_path);
+ PyMem_FREE(name);
+ return &importhookdescr;
+ }
+ Py_DECREF(loader);
+ }
+ Py_DECREF(meta_path);
+ }
+
+ if (path != NULL && PyString_Check(path)) {
+ /* The only type of submodule allowed inside a "frozen"
+ package are other frozen modules or packages. */
+ if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) {
+ PyErr_SetString(PyExc_ImportError,
+ "full frozen module name too long");
+ goto error_exit;
+ }
+ strcpy(buf, PyString_AsString(path));
+ strcat(buf, ".");
+ strcat(buf, name);
+ strcpy(name, buf);
+ if (find_frozen(name) != NULL) {
+ strcpy(buf, name);
+ PyMem_FREE(name);
+ return &fd_frozen;
+ }
+ PyErr_Format(PyExc_ImportError,
+ "No frozen submodule named %.200s", name);
+ goto error_exit;
+ }
+ if (fullname != NULL && is_builtin(fullname)) {
+ PyMem_FREE(name);
+ strcpy(buf, fullname);
+ return &fd_builtin;
+ }
+ if (path == NULL) {
+ if (is_builtin(name)) {
+ strcpy(buf, name);
+ PyMem_FREE(name);
+ return &fd_builtin;
+ }
+ if ((find_frozen(name)) != NULL) {
+ strcpy(buf, name);
+ PyMem_FREE(name);
+ return &fd_frozen;
+ }
+
+#ifdef MS_COREDLL
+ fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen);
+ if (fp != NULL) {
+ *p_fp = fp;
+ PyMem_FREE(name);
+ return fdp;
+ }
+#endif
+ path = PySys_GetObject("path");
+ }
+ if (path == NULL || !PyList_Check(path)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "sys.path must be a list of directory names");
+ goto error_exit;
+ }
+
+ path_hooks = PySys_GetObject("path_hooks");
+ if (path_hooks == NULL || !PyList_Check(path_hooks)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "sys.path_hooks must be a list of "
+ "import hooks");
+ goto error_exit;
+ }
+ path_importer_cache = PySys_GetObject("path_importer_cache");
+ if (path_importer_cache == NULL ||
+ !PyDict_Check(path_importer_cache)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "sys.path_importer_cache must be a dict");
+ goto error_exit;
+ }
+
+ npath = PyList_Size(path);
+ namelen = strlen(name);
+ for (i = 0; i < npath; i++) {
+ PyObject *copy = NULL;
+ PyObject *v = PyList_GetItem(path, i);
+ if (!v)
+ goto error_exit;
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(v)) {
+ copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v),
+ PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL);
+ if (copy == NULL)
+ goto error_exit;
+ v = copy;
+ }
+ else
+#endif
+ if (!PyString_Check(v))
+ continue;
+ len = PyString_GET_SIZE(v);
+ if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) {
+ Py_XDECREF(copy);
+ continue; /* Too long */
+ }
+ strcpy(buf, PyString_AS_STRING(v));
+ if (strlen(buf) != len) {
+ Py_XDECREF(copy);
+ continue; /* v contains '\0' */
+ }
+
+ /* sys.path_hooks import hook */
+ if (p_loader != NULL) {
+ PyObject *importer;
+
+ importer = get_path_importer(path_importer_cache,
+ path_hooks, v);
+ if (importer == NULL) {
+ Py_XDECREF(copy);
+ goto error_exit;
+ }
+ /* Note: importer is a borrowed reference */
+ if (importer != Py_None) {
+ PyObject *loader;
+ loader = PyObject_CallMethod(importer,
+ "find_module",
+ "s", fullname);
+ Py_XDECREF(copy);
+ if (loader == NULL)
+ goto error_exit; /* error */
+ if (loader != Py_None) {
+ /* a loader was found */
+ *p_loader = loader;
+ PyMem_FREE(name);
+ return &importhookdescr;
+ }
+ Py_DECREF(loader);
+ continue;
+ }
+ }
+ /* no hook was found, use builtin import */
+
+ if (len > 0 && buf[len-1] != SEP
+#ifdef ALTSEP
+ && buf[len-1] != ALTSEP
+#endif
+ )
+ buf[len++] = SEP;
+ strcpy(buf+len, name);
+ len += namelen;
+
+ /* Check for package import (buf holds a directory name,
+ and there's an __init__ module in that directory */
+ if (isdir(buf) && /* it's an existing directory */
+ case_ok(buf, len, namelen, name)) { /* case matches */
+ if (find_init_module(buf)) { /* and has __init__.py */
+ Py_XDECREF(copy);
+ PyMem_FREE(name);
+ return &fd_package;
+ }
+ else {
+ char warnstr[MAXPATHLEN+80];
+ sprintf(warnstr, "Not importing directory "
+ "'%.*s': missing __init__.py",
+ MAXPATHLEN, buf);
+ if (PyErr_Warn(PyExc_ImportWarning,
+ warnstr)) {
+ Py_XDECREF(copy);
+ goto error_exit;
+ }
+ }
+ }
+#if defined(PYOS_OS2)
+ /* take a snapshot of the module spec for restoration
+ * after the 8 character DLL hackery
+ */
+ saved_buf = strdup(buf);
+ saved_len = len;
+ saved_namelen = namelen;
+#endif /* PYOS_OS2 */
+ for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
+#if defined(PYOS_OS2) && defined(HAVE_DYNAMIC_LOADING)
+ /* OS/2 limits DLLs to 8 character names (w/o
+ extension)
+ * so if the name is longer than that and its a
+ * dynamically loaded module we're going to try,
+ * truncate the name before trying
+ */
+ if (strlen(subname) > 8) {
+ /* is this an attempt to load a C extension? */
+ const struct filedescr *scan;
+ scan = _PyImport_DynLoadFiletab;
+ while (scan->suffix != NULL) {
+ if (!strcmp(scan->suffix, fdp->suffix))
+ break;
+ else
+ scan++;
+ }
+ if (scan->suffix != NULL) {
+ /* yes, so truncate the name */
+ namelen = 8;
+ len -= strlen(subname) - namelen;
+ buf[len] = '\0';
+ }
+ }
+#endif /* PYOS_OS2 */
+ strcpy(buf+len, fdp->suffix);
+ if (Py_VerboseFlag > 1)
+ PySys_WriteStderr("# trying %s\n", buf);
+ filemode = fdp->mode;
+ if (filemode[0] == 'U')
+ filemode = "r" PY_STDIOTEXTMODE;
+ fp = fopen(buf, filemode);
+ if (fp != NULL) {
+ if (case_ok(buf, len, namelen, name))
+ break;
+ else { /* continue search */
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+#if defined(PYOS_OS2)
+ /* restore the saved snapshot */
+ strcpy(buf, saved_buf);
+ len = saved_len;
+ namelen = saved_namelen;
+#endif
+ }
+#if defined(PYOS_OS2)
+ /* don't need/want the module name snapshot anymore */
+ if (saved_buf)
+ {
+ free(saved_buf);
+ saved_buf = NULL;
+ }
+#endif
+ Py_XDECREF(copy);
+ if (fp != NULL)
+ break;
+ }
+ if (fp == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "No module named %.200s", name);
+ goto error_exit;
+ }
+ *p_fp = fp;
+ PyMem_FREE(name);
+ return fdp;
+
+error_exit:
+ PyMem_FREE(name);
+ return NULL;
+}
+
+/* Helpers for main.c
+ * Find the source file corresponding to a named module
+ */
+struct filedescr *
+_PyImport_FindModule(const char *name, PyObject *path, char *buf,
+ size_t buflen, FILE **p_fp, PyObject **p_loader)
+{
+ return find_module((char *) name, (char *) name, path,
+ buf, buflen, p_fp, p_loader);
+}
+
+PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd)
+{
+ return fd->type == PY_SOURCE || fd->type == PY_COMPILED;
+}
+
+/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name)
+ * The arguments here are tricky, best shown by example:
+ * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0
+ * ^ ^ ^ ^
+ * |--------------------- buf ---------------------|
+ * |------------------- len ------------------|
+ * |------ name -------|
+ * |----- namelen -----|
+ * buf is the full path, but len only counts up to (& exclusive of) the
+ * extension. name is the module name, also exclusive of extension.
+ *
+ * We've already done a successful stat() or fopen() on buf, so know that
+ * there's some match, possibly case-insensitive.
+ *
+ * case_ok() is to return 1 if there's a case-sensitive match for
+ * name, else 0. case_ok() is also to return 1 if envar PYTHONCASEOK
+ * exists.
+ *
+ * case_ok() is used to implement case-sensitive import semantics even
+ * on platforms with case-insensitive filesystems. It's trivial to implement
+ * for case-sensitive filesystems. It's pretty much a cross-platform
+ * nightmare for systems with case-insensitive filesystems.
+ */
+
+/* First we may need a pile of platform-specific header files; the sequence
+ * of #if's here should match the sequence in the body of case_ok().
+ */
+#if defined(MS_WINDOWS)
+#include <windows.h>
+
+#elif defined(DJGPP)
+#include <dir.h>
+
+#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H)
+#include <sys/types.h>
+#include <dirent.h>
+
+#elif defined(PYOS_OS2)
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_NOPMAPI
+#include <os2.h>
+
+#elif defined(RISCOS)
+#include "oslib/osfscontrol.h"
+#endif
+
+static int
+case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name)
+{
+/* Pick a platform-specific implementation; the sequence of #if's here should
+ * match the sequence just above.
+ */
+
+/* MS_WINDOWS */
+#if defined(MS_WINDOWS)
+ WIN32_FIND_DATA data;
+ HANDLE h;
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ h = FindFirstFile(buf, &data);
+ if (h == INVALID_HANDLE_VALUE) {
+ PyErr_Format(PyExc_NameError,
+ "Can't find file for module %.100s\n(filename %.300s)",
+ name, buf);
+ return 0;
+ }
+ FindClose(h);
+ return strncmp(data.cFileName, name, namelen) == 0;
+
+/* DJGPP */
+#elif defined(DJGPP)
+ struct ffblk ffblk;
+ int done;
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC);
+ if (done) {
+ PyErr_Format(PyExc_NameError,
+ "Can't find file for module %.100s\n(filename %.300s)",
+ name, buf);
+ return 0;
+ }
+ return strncmp(ffblk.ff_name, name, namelen) == 0;
+
+/* new-fangled macintosh (macosx) or Cygwin */
+#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H)
+ DIR *dirp;
+ struct dirent *dp;
+ char dirname[MAXPATHLEN + 1];
+ const int dirlen = len - namelen - 1; /* don't want trailing SEP */
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ /* Copy the dir component into dirname; substitute "." if empty */
+ if (dirlen <= 0) {
+ dirname[0] = '.';
+ dirname[1] = '\0';
+ }
+ else {
+ assert(dirlen <= MAXPATHLEN);
+ memcpy(dirname, buf, dirlen);
+ dirname[dirlen] = '\0';
+ }
+ /* Open the directory and search the entries for an exact match. */
+ dirp = opendir(dirname);
+ if (dirp) {
+ char *nameWithExt = buf + len - namelen;
+ while ((dp = readdir(dirp)) != NULL) {
+ const int thislen =
+#ifdef _DIRENT_HAVE_D_NAMELEN
+ dp->d_namlen;
+#else
+ strlen(dp->d_name);
+#endif
+ if (thislen >= namelen &&
+ strcmp(dp->d_name, nameWithExt) == 0) {
+ (void)closedir(dirp);
+ return 1; /* Found */
+ }
+ }
+ (void)closedir(dirp);
+ }
+ return 0 ; /* Not found */
+
+/* RISC OS */
+#elif defined(RISCOS)
+ char canon[MAXPATHLEN+1]; /* buffer for the canonical form of the path */
+ char buf2[MAXPATHLEN+2];
+ char *nameWithExt = buf+len-namelen;
+ int canonlen;
+ os_error *e;
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ /* workaround:
+ append wildcard, otherwise case of filename wouldn't be touched */
+ strcpy(buf2, buf);
+ strcat(buf2, "*");
+
+ e = xosfscontrol_canonicalise_path(buf2,canon,0,0,MAXPATHLEN+1,&canonlen);
+ canonlen = MAXPATHLEN+1-canonlen;
+ if (e || canonlen<=0 || canonlen>(MAXPATHLEN+1) )
+ return 0;
+ if (strcmp(nameWithExt, canon+canonlen-strlen(nameWithExt))==0)
+ return 1; /* match */
+
+ return 0;
+
+/* OS/2 */
+#elif defined(PYOS_OS2)
+ HDIR hdir = 1;
+ ULONG srchcnt = 1;
+ FILEFINDBUF3 ffbuf;
+ APIRET rc;
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ rc = DosFindFirst(buf,
+ &hdir,
+ FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY,
+ &ffbuf, sizeof(ffbuf),
+ &srchcnt,
+ FIL_STANDARD);
+ if (rc != NO_ERROR)
+ return 0;
+ return strncmp(ffbuf.achName, name, namelen) == 0;
+
+/* assuming it's a case-sensitive filesystem, so there's nothing to do! */
+#else
+ return 1;
+
+#endif
+}
+
+
+#ifdef HAVE_STAT
+/* Helper to look for __init__.py or __init__.py[co] in potential package */
+static int
+find_init_module(char *buf)
+{
+ const size_t save_len = strlen(buf);
+ size_t i = save_len;
+ char *pname; /* pointer to start of __init__ */
+ struct stat statbuf;
+
+/* For calling case_ok(buf, len, namelen, name):
+ * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0
+ * ^ ^ ^ ^
+ * |--------------------- buf ---------------------|
+ * |------------------- len ------------------|
+ * |------ name -------|
+ * |----- namelen -----|
+ */
+ if (save_len + 13 >= MAXPATHLEN)
+ return 0;
+ buf[i++] = SEP;
+ pname = buf + i;
+ strcpy(pname, "__init__.py");
+ if (stat(buf, &statbuf) == 0) {
+ if (case_ok(buf,
+ save_len + 9, /* len("/__init__") */
+ 8, /* len("__init__") */
+ pname)) {
+ buf[save_len] = '\0';
+ return 1;
+ }
+ }
+ i += strlen(pname);
+ strcpy(buf+i, Py_OptimizeFlag ? "o" : "c");
+ if (stat(buf, &statbuf) == 0) {
+ if (case_ok(buf,
+ save_len + 9, /* len("/__init__") */
+ 8, /* len("__init__") */
+ pname)) {
+ buf[save_len] = '\0';
+ return 1;
+ }
+ }
+ buf[save_len] = '\0';
+ return 0;
+}
+
+#else
+
+#ifdef RISCOS
+static int
+find_init_module(buf)
+ char *buf;
+{
+ int save_len = strlen(buf);
+ int i = save_len;
+
+ if (save_len + 13 >= MAXPATHLEN)
+ return 0;
+ buf[i++] = SEP;
+ strcpy(buf+i, "__init__/py");
+ if (isfile(buf)) {
+ buf[save_len] = '\0';
+ return 1;
+ }
+
+ if (Py_OptimizeFlag)
+ strcpy(buf+i, "o");
+ else
+ strcpy(buf+i, "c");
+ if (isfile(buf)) {
+ buf[save_len] = '\0';
+ return 1;
+ }
+ buf[save_len] = '\0';
+ return 0;
+}
+#endif /*RISCOS*/
+
+#endif /* HAVE_STAT */
+
+
+static int init_builtin(char *); /* Forward */
+
+/* Load an external module using the default search path and return
+ its module object WITH INCREMENTED REFERENCE COUNT */
+
+static PyObject *
+load_module(char *name, FILE *fp, char *pathname, int type, PyObject *loader)
+{
+ PyObject *modules;
+ PyObject *m;
+ int err;
+
+ /* First check that there's an open file (if we need one) */
+ switch (type) {
+ case PY_SOURCE:
+ case PY_COMPILED:
+ if (fp == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "file object required for import (type code %d)",
+ type);
+ return NULL;
+ }
+ }
+
+ switch (type) {
+
+ case PY_SOURCE:
+ m = load_source_module(name, pathname, fp);
+ break;
+
+ case PY_COMPILED:
+ m = load_compiled_module(name, pathname, fp);
+ break;
+
+#ifdef HAVE_DYNAMIC_LOADING
+ case C_EXTENSION:
+ m = _PyImport_LoadDynamicModule(name, pathname, fp);
+ break;
+#endif
+
+ case PKG_DIRECTORY:
+ m = load_package(name, pathname);
+ break;
+
+ case C_BUILTIN:
+ case PY_FROZEN:
+ if (pathname != NULL && pathname[0] != '\0')
+ name = pathname;
+ if (type == C_BUILTIN)
+ err = init_builtin(name);
+ else
+ err = PyImport_ImportFrozenModule(name);
+ if (err < 0)
+ return NULL;
+ if (err == 0) {
+ PyErr_Format(PyExc_ImportError,
+ "Purported %s module %.200s not found",
+ type == C_BUILTIN ?
+ "builtin" : "frozen",
+ name);
+ return NULL;
+ }
+ modules = PyImport_GetModuleDict();
+ m = PyDict_GetItemString(modules, name);
+ if (m == NULL) {
+ PyErr_Format(
+ PyExc_ImportError,
+ "%s module %.200s not properly initialized",
+ type == C_BUILTIN ?
+ "builtin" : "frozen",
+ name);
+ return NULL;
+ }
+ Py_INCREF(m);
+ break;
+
+ case IMP_HOOK: {
+ if (loader == NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "import hook without loader");
+ return NULL;
+ }
+ m = PyObject_CallMethod(loader, "load_module", "s", name);
+ break;
+ }
+
+ default:
+ PyErr_Format(PyExc_ImportError,
+ "Don't know how to import %.200s (type code %d)",
+ name, type);
+ m = NULL;
+
+ }
+
+ return m;
+}
+
+
+/* Initialize a built-in module.
+ Return 1 for success, 0 if the module is not found, and -1 with
+ an exception set if the initialization failed. */
+
+static int
+init_builtin(char *name)
+{
+ struct _inittab *p;
+ char *oldcontext;
+
+ if (_PyImport_FindExtension(name, name) != NULL)
+ return 1;
+
+ for (p = PyImport_Inittab; p->name != NULL; p++) {
+ if (strcmp(name, p->name) == 0) {
+ if (p->initfunc == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "Cannot re-init internal module %.200s",
+ name);
+ return -1;
+ }
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # builtin\n", name);
+ oldcontext = _Py_PackageContext;
+ _Py_PackageContext = name;
+ (*p->initfunc)();
+ _Py_PackageContext = oldcontext;
+ if (PyErr_Occurred())
+ return -1;
+ if (_PyImport_FixupExtension(name, name) == NULL)
+ return -1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* Frozen modules */
+
+static struct _frozen *
+find_frozen(char *name)
+{
+ struct _frozen *p;
+
+ for (p = PyImport_FrozenModules; ; p++) {
+ if (p->name == NULL)
+ return NULL;
+ if (strcmp(p->name, name) == 0)
+ break;
+ }
+ return p;
+}
+
+static PyObject *
+get_frozen_object(char *name)
+{
+ struct _frozen *p = find_frozen(name);
+ int size;
+
+ if (p == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "No such frozen object named %.200s",
+ name);
+ return NULL;
+ }
+ if (p->code == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "Excluded frozen object named %.200s",
+ name);
+ return NULL;
+ }
+ size = p->size;
+ if (size < 0)
+ size = -size;
+ return PyMarshal_ReadObjectFromString((char *)p->code, size);
+}
+
+/* Initialize a frozen module.
+ Return 1 for succes, 0 if the module is not found, and -1 with
+ an exception set if the initialization failed.
+ This function is also used from frozenmain.c */
+
+int
+PyImport_ImportFrozenModule(char *name)
+{
+ struct _frozen *p = find_frozen(name);
+ PyObject *co;
+ PyObject *m;
+ int ispackage;
+ int size;
+
+ if (p == NULL)
+ return 0;
+ if (p->code == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "Excluded frozen object named %.200s",
+ name);
+ return -1;
+ }
+ size = p->size;
+ ispackage = (size < 0);
+ if (ispackage)
+ size = -size;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("import %s # frozen%s\n",
+ name, ispackage ? " package" : "");
+ co = PyMarshal_ReadObjectFromString((char *)p->code, size);
+ if (co == NULL)
+ return -1;
+ if (!PyCode_Check(co)) {
+ PyErr_Format(PyExc_TypeError,
+ "frozen object %.200s is not a code object",
+ name);
+ goto err_return;
+ }
+ if (ispackage) {
+ /* Set __path__ to the package name */
+ PyObject *d, *s;
+ int err;
+ m = PyImport_AddModule(name);
+ if (m == NULL)
+ goto err_return;
+ d = PyModule_GetDict(m);
+ s = PyString_InternFromString(name);
+ if (s == NULL)
+ goto err_return;
+ err = PyDict_SetItemString(d, "__path__", s);
+ Py_DECREF(s);
+ if (err != 0)
+ goto err_return;
+ }
+ m = PyImport_ExecCodeModuleEx(name, co, "<frozen>");
+ if (m == NULL)
+ goto err_return;
+ Py_DECREF(co);
+ Py_DECREF(m);
+ return 1;
+err_return:
+ Py_DECREF(co);
+ return -1;
+}
+
+
+/* Import a module, either built-in, frozen, or external, and return
+ its module object WITH INCREMENTED REFERENCE COUNT */
+
+PyObject *
+PyImport_ImportModule(const char *name)
+{
+ PyObject *pname;
+ PyObject *result;
+
+ pname = PyString_FromString(name);
+ if (pname == NULL)
+ return NULL;
+ result = PyImport_Import(pname);
+ Py_DECREF(pname);
+ return result;
+}
+
+/* Import a module without blocking
+ *
+ * At first it tries to fetch the module from sys.modules. If the module was
+ * never loaded before it loads it with PyImport_ImportModule() unless another
+ * thread holds the import lock. In the latter case the function raises an
+ * ImportError instead of blocking.
+ *
+ * Returns the module object with incremented ref count.
+ */
+PyObject *
+PyImport_ImportModuleNoBlock(const char *name)
+{
+ PyObject *result;
+ PyObject *modules;
+#ifdef WITH_THREAD
+ long me;
+#endif
+
+ /* Try to get the module from sys.modules[name] */
+ modules = PyImport_GetModuleDict();
+ if (modules == NULL)
+ return NULL;
+
+ result = PyDict_GetItemString(modules, name);
+ if (result != NULL) {
+ Py_INCREF(result);
+ return result;
+ }
+ else {
+ PyErr_Clear();
+ }
+#ifdef WITH_THREAD
+ /* check the import lock
+ * me might be -1 but I ignore the error here, the lock function
+ * takes care of the problem */
+ me = PyThread_get_thread_ident();
+ if (import_lock_thread == -1 || import_lock_thread == me) {
+ /* no thread or me is holding the lock */
+ return PyImport_ImportModule(name);
+ }
+ else {
+ PyErr_Format(PyExc_ImportError,
+ "Failed to import %.200s because the import lock"
+ "is held by another thread.",
+ name);
+ return NULL;
+ }
+#else
+ return PyImport_ImportModule(name);
+#endif
+}
+
+/* Forward declarations for helper routines */
+static PyObject *get_parent(PyObject *globals, char *buf,
+ Py_ssize_t *p_buflen, int level);
+static PyObject *load_next(PyObject *mod, PyObject *altmod,
+ char **p_name, char *buf, Py_ssize_t *p_buflen);
+static int mark_miss(char *name);
+static int ensure_fromlist(PyObject *mod, PyObject *fromlist,
+ char *buf, Py_ssize_t buflen, int recursive);
+static PyObject * import_submodule(PyObject *mod, char *name, char *fullname);
+
+/* The Magnum Opus of dotted-name import :-) */
+
+static PyObject *
+import_module_level(char *name, PyObject *globals, PyObject *locals,
+ PyObject *fromlist, int level)
+{
+ char *buf;
+ Py_ssize_t buflen = 0;
+ PyObject *parent, *head, *next, *tail;
+
+ if (strchr(name, '/') != NULL
+#ifdef MS_WINDOWS
+ || strchr(name, '\\') != NULL
+#endif
+ ) {
+ PyErr_SetString(PyExc_ImportError,
+ "Import by filename is not supported.");
+ return NULL;
+ }
+
+ buf = PyMem_MALLOC(MAXPATHLEN+1);
+ if (buf == NULL) {
+ return PyErr_NoMemory();
+ }
+ parent = get_parent(globals, buf, &buflen, level);
+ if (parent == NULL)
+ goto error_exit;
+
+ Py_INCREF(parent);
+ head = load_next(parent, level < 0 ? Py_None : parent, &name, buf,
+ &buflen);
+ Py_DECREF(parent);
+ if (head == NULL)
+ goto error_exit;
+
+ tail = head;
+ Py_INCREF(tail);
+ while (name) {
+ next = load_next(tail, tail, &name, buf, &buflen);
+ Py_DECREF(tail);
+ if (next == NULL) {
+ Py_DECREF(head);
+ goto error_exit;
+ }
+ tail = next;
+ }
+ if (tail == Py_None) {
+ /* If tail is Py_None, both get_parent and load_next found
+ an empty module name: someone called __import__("") or
+ doctored faulty bytecode */
+ Py_DECREF(tail);
+ Py_DECREF(head);
+ PyErr_SetString(PyExc_ValueError,
+ "Empty module name");
+ goto error_exit;
+ }
+
+ if (fromlist != NULL) {
+ int b = (fromlist == Py_None) ? 0 : PyObject_IsTrue(fromlist);
+ if (b < 0) {
+ Py_DECREF(tail);
+ Py_DECREF(head);
+ goto error_exit;
+ }
+ if (!b)
+ fromlist = NULL;
+ }
+
+ if (fromlist == NULL) {
+ Py_DECREF(tail);
+ PyMem_FREE(buf);
+ return head;
+ }
+
+ Py_DECREF(head);
+ if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) {
+ Py_DECREF(tail);
+ goto error_exit;
+ }
+
+ PyMem_FREE(buf);
+ return tail;
+
+error_exit:
+ PyMem_FREE(buf);
+ return NULL;
+}
+
+PyObject *
+PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals,
+ PyObject *fromlist, int level)
+{
+ PyObject *result;
+ _PyImport_AcquireLock();
+ result = import_module_level(name, globals, locals, fromlist, level);
+ if (_PyImport_ReleaseLock() < 0) {
+ Py_XDECREF(result);
+ PyErr_SetString(PyExc_RuntimeError,
+ "not holding the import lock");
+ return NULL;
+ }
+ return result;
+}
+
+/* Return the package that an import is being performed in. If globals comes
+ from the module foo.bar.bat (not itself a package), this returns the
+ sys.modules entry for foo.bar. If globals is from a package's __init__.py,
+ the package's entry in sys.modules is returned, as a borrowed reference.
+
+ The *name* of the returned package is returned in buf, with the length of
+ the name in *p_buflen.
+
+ If globals doesn't come from a package or a module in a package, or a
+ corresponding entry is not found in sys.modules, Py_None is returned.
+*/
+static PyObject *
+get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
+{
+ static PyObject *namestr = NULL;
+ static PyObject *pathstr = NULL;
+ static PyObject *pkgstr = NULL;
+ PyObject *pkgname, *modname, *modpath, *modules, *parent;
+ int orig_level = level;
+
+ if (globals == NULL || !PyDict_Check(globals) || !level)
+ return Py_None;
+
+ if (namestr == NULL) {
+ namestr = PyString_InternFromString("__name__");
+ if (namestr == NULL)
+ return NULL;
+ }
+ if (pathstr == NULL) {
+ pathstr = PyString_InternFromString("__path__");
+ if (pathstr == NULL)
+ return NULL;
+ }
+ if (pkgstr == NULL) {
+ pkgstr = PyString_InternFromString("__package__");
+ if (pkgstr == NULL)
+ return NULL;
+ }
+
+ *buf = '\0';
+ *p_buflen = 0;
+ pkgname = PyDict_GetItem(globals, pkgstr);
+
+ if ((pkgname != NULL) && (pkgname != Py_None)) {
+ /* __package__ is set, so use it */
+ Py_ssize_t len;
+ if (!PyString_Check(pkgname)) {
+ PyErr_SetString(PyExc_ValueError,
+ "__package__ set to non-string");
+ return NULL;
+ }
+ len = PyString_GET_SIZE(pkgname);
+ if (len == 0) {
+ if (level > 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Attempted relative import in non-package");
+ return NULL;
+ }
+ return Py_None;
+ }
+ if (len > MAXPATHLEN) {
+ PyErr_SetString(PyExc_ValueError,
+ "Package name too long");
+ return NULL;
+ }
+ strcpy(buf, PyString_AS_STRING(pkgname));
+ } else {
+ /* __package__ not set, so figure it out and set it */
+ modname = PyDict_GetItem(globals, namestr);
+ if (modname == NULL || !PyString_Check(modname))
+ return Py_None;
+
+ modpath = PyDict_GetItem(globals, pathstr);
+ if (modpath != NULL) {
+ /* __path__ is set, so modname is already the package name */
+ Py_ssize_t len = PyString_GET_SIZE(modname);
+ int error;
+ if (len > MAXPATHLEN) {
+ PyErr_SetString(PyExc_ValueError,
+ "Module name too long");
+ return NULL;
+ }
+ strcpy(buf, PyString_AS_STRING(modname));
+ error = PyDict_SetItem(globals, pkgstr, modname);
+ if (error) {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not set __package__");
+ return NULL;
+ }
+ } else {
+ /* Normal module, so work out the package name if any */
+ char *start = PyString_AS_STRING(modname);
+ char *lastdot = strrchr(start, '.');
+ size_t len;
+ int error;
+ if (lastdot == NULL && level > 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Attempted relative import in non-package");
+ return NULL;
+ }
+ if (lastdot == NULL) {
+ error = PyDict_SetItem(globals, pkgstr, Py_None);
+ if (error) {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not set __package__");
+ return NULL;
+ }
+ return Py_None;
+ }
+ len = lastdot - start;
+ if (len >= MAXPATHLEN) {
+ PyErr_SetString(PyExc_ValueError,
+ "Module name too long");
+ return NULL;
+ }
+ strncpy(buf, start, len);
+ buf[len] = '\0';
+ pkgname = PyString_FromString(buf);
+ if (pkgname == NULL) {
+ return NULL;
+ }
+ error = PyDict_SetItem(globals, pkgstr, pkgname);
+ Py_DECREF(pkgname);
+ if (error) {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not set __package__");
+ return NULL;
+ }
+ }
+ }
+ while (--level > 0) {
+ char *dot = strrchr(buf, '.');
+ if (dot == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Attempted relative import beyond "
+ "toplevel package");
+ return NULL;
+ }
+ *dot = '\0';
+ }
+ *p_buflen = strlen(buf);
+
+ modules = PyImport_GetModuleDict();
+ parent = PyDict_GetItemString(modules, buf);
+ if (parent == NULL) {
+ if (orig_level < 1) {
+ PyObject *err_msg = PyString_FromFormat(
+ "Parent module '%.200s' not found "
+ "while handling absolute import", buf);
+ if (err_msg == NULL) {
+ return NULL;
+ }
+ if (!PyErr_WarnEx(PyExc_RuntimeWarning,
+ PyString_AsString(err_msg), 1)) {
+ *buf = '\0';
+ *p_buflen = 0;
+ parent = Py_None;
+ }
+ Py_DECREF(err_msg);
+ } else {
+ PyErr_Format(PyExc_SystemError,
+ "Parent module '%.200s' not loaded, "
+ "cannot perform relative import", buf);
+ }
+ }
+ return parent;
+ /* We expect, but can't guarantee, if parent != None, that:
+ - parent.__name__ == buf
+ - parent.__dict__ is globals
+ If this is violated... Who cares? */
+}
+
+/* altmod is either None or same as mod */
+static PyObject *
+load_next(PyObject *mod, PyObject *altmod, char **p_name, char *buf,
+ Py_ssize_t *p_buflen)
+{
+ char *name = *p_name;
+ char *dot = strchr(name, '.');
+ size_t len;
+ char *p;
+ PyObject *result;
+
+ if (strlen(name) == 0) {
+ /* completely empty module name should only happen in
+ 'from . import' (or '__import__("")')*/
+ Py_INCREF(mod);
+ *p_name = NULL;
+ return mod;
+ }
+
+ if (dot == NULL) {
+ *p_name = NULL;
+ len = strlen(name);
+ }
+ else {
+ *p_name = dot+1;
+ len = dot-name;
+ }
+ if (len == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Empty module name");
+ return NULL;
+ }
+
+ p = buf + *p_buflen;
+ if (p != buf)
+ *p++ = '.';
+ if (p+len-buf >= MAXPATHLEN) {
+ PyErr_SetString(PyExc_ValueError,
+ "Module name too long");
+ return NULL;
+ }
+ strncpy(p, name, len);
+ p[len] = '\0';
+ *p_buflen = p+len-buf;
+
+ result = import_submodule(mod, p, buf);
+ if (result == Py_None && altmod != mod) {
+ Py_DECREF(result);
+ /* Here, altmod must be None and mod must not be None */
+ result = import_submodule(altmod, p, p);
+ if (result != NULL && result != Py_None) {
+ if (mark_miss(buf) != 0) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ strncpy(buf, name, len);
+ buf[len] = '\0';
+ *p_buflen = len;
+ }
+ }
+ if (result == NULL)
+ return NULL;
+
+ if (result == Py_None) {
+ Py_DECREF(result);
+ PyErr_Format(PyExc_ImportError,
+ "No module named %.200s", name);
+ return NULL;
+ }
+
+ return result;
+}
+
+static int
+mark_miss(char *name)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ return PyDict_SetItemString(modules, name, Py_None);
+}
+
+static int
+ensure_fromlist(PyObject *mod, PyObject *fromlist, char *buf, Py_ssize_t buflen,
+ int recursive)
+{
+ int i;
+
+ if (!PyObject_HasAttrString(mod, "__path__"))
+ return 1;
+
+ for (i = 0; ; i++) {
+ PyObject *item = PySequence_GetItem(fromlist, i);
+ int hasit;
+ if (item == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_IndexError)) {
+ PyErr_Clear();
+ return 1;
+ }
+ return 0;
+ }
+ if (!PyString_Check(item)) {
+ PyErr_Format(PyExc_TypeError,
+ "Item in ``from list'' must be str, not %.200s",
+ Py_TYPE(item)->tp_name);
+ Py_DECREF(item);
+ return 0;
+ }
+ if (PyString_AS_STRING(item)[0] == '*') {
+ PyObject *all;
+ Py_DECREF(item);
+ /* See if the package defines __all__ */
+ if (recursive)
+ continue; /* Avoid endless recursion */
+ all = PyObject_GetAttrString(mod, "__all__");
+ if (all == NULL)
+ PyErr_Clear();
+ else {
+ int ret = ensure_fromlist(mod, all, buf, buflen, 1);
+ Py_DECREF(all);
+ if (!ret)
+ return 0;
+ }
+ continue;
+ }
+ hasit = PyObject_HasAttr(mod, item);
+ if (!hasit) {
+ char *subname = PyString_AS_STRING(item);
+ PyObject *submod;
+ char *p;
+ if (buflen + strlen(subname) >= MAXPATHLEN) {
+ PyErr_SetString(PyExc_ValueError,
+ "Module name too long");
+ Py_DECREF(item);
+ return 0;
+ }
+ p = buf + buflen;
+ *p++ = '.';
+ strcpy(p, subname);
+ submod = import_submodule(mod, subname, buf);
+ Py_XDECREF(submod);
+ if (submod == NULL) {
+ Py_DECREF(item);
+ return 0;
+ }
+ }
+ Py_DECREF(item);
+ }
+
+ /* NOTREACHED */
+}
+
+static int
+add_submodule(PyObject *mod, PyObject *submod, char *fullname, char *subname,
+ PyObject *modules)
+{
+ if (mod == Py_None)
+ return 1;
+ /* Irrespective of the success of this load, make a
+ reference to it in the parent package module. A copy gets
+ saved in the modules dictionary under the full name, so get a
+ reference from there, if need be. (The exception is when the
+ load failed with a SyntaxError -- then there's no trace in
+ sys.modules. In that case, of course, do nothing extra.) */
+ if (submod == NULL) {
+ submod = PyDict_GetItemString(modules, fullname);
+ if (submod == NULL)
+ return 1;
+ }
+ if (PyModule_Check(mod)) {
+ /* We can't use setattr here since it can give a
+ * spurious warning if the submodule name shadows a
+ * builtin name */
+ PyObject *dict = PyModule_GetDict(mod);
+ if (!dict)
+ return 0;
+ if (PyDict_SetItemString(dict, subname, submod) < 0)
+ return 0;
+ }
+ else {
+ if (PyObject_SetAttrString(mod, subname, submod) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+static PyObject *
+import_submodule(PyObject *mod, char *subname, char *fullname)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *m = NULL;
+
+ /* Require:
+ if mod == None: subname == fullname
+ else: mod.__name__ + "." + subname == fullname
+ */
+
+ if ((m = PyDict_GetItemString(modules, fullname)) != NULL) {
+ Py_INCREF(m);
+ }
+ else {
+ PyObject *path, *loader = NULL;
+ char *buf;
+ struct filedescr *fdp;
+ FILE *fp = NULL;
+
+ if (mod == Py_None)
+ path = NULL;
+ else {
+ path = PyObject_GetAttrString(mod, "__path__");
+ if (path == NULL) {
+ PyErr_Clear();
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ }
+
+ buf = PyMem_MALLOC(MAXPATHLEN+1);
+ if (buf == NULL) {
+ return PyErr_NoMemory();
+ }
+ buf[0] = '\0';
+ fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1,
+ &fp, &loader);
+ Py_XDECREF(path);
+ if (fdp == NULL) {
+ PyMem_FREE(buf);
+ if (!PyErr_ExceptionMatches(PyExc_ImportError))
+ return NULL;
+ PyErr_Clear();
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ m = load_module(fullname, fp, buf, fdp->type, loader);
+ Py_XDECREF(loader);
+ if (fp)
+ fclose(fp);
+ if (!add_submodule(mod, m, fullname, subname, modules)) {
+ Py_XDECREF(m);
+ m = NULL;
+ }
+ PyMem_FREE(buf);
+ }
+
+ return m;
+}
+
+
+/* Re-import a module of any kind and return its module object, WITH
+ INCREMENTED REFERENCE COUNT */
+
+PyObject *
+PyImport_ReloadModule(PyObject *m)
+{
+ PyInterpreterState *interp = PyThreadState_Get()->interp;
+ PyObject *modules_reloading = interp->modules_reloading;
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *path = NULL, *loader = NULL, *existing_m = NULL;
+ char *name, *subname;
+ char *buf;
+ struct filedescr *fdp;
+ FILE *fp = NULL;
+ PyObject *newm;
+
+ if (modules_reloading == NULL) {
+ Py_FatalError("PyImport_ReloadModule: "
+ "no modules_reloading dictionary!");
+ return NULL;
+ }
+
+ if (m == NULL || !PyModule_Check(m)) {
+ PyErr_SetString(PyExc_TypeError,
+ "reload() argument must be module");
+ return NULL;
+ }
+ name = PyModule_GetName(m);
+ if (name == NULL)
+ return NULL;
+ if (m != PyDict_GetItemString(modules, name)) {
+ PyErr_Format(PyExc_ImportError,
+ "reload(): module %.200s not in sys.modules",
+ name);
+ return NULL;
+ }
+ existing_m = PyDict_GetItemString(modules_reloading, name);
+ if (existing_m != NULL) {
+ /* Due to a recursive reload, this module is already
+ being reloaded. */
+ Py_INCREF(existing_m);
+ return existing_m;
+ }
+ if (PyDict_SetItemString(modules_reloading, name, m) < 0)
+ return NULL;
+
+ subname = strrchr(name, '.');
+ if (subname == NULL)
+ subname = name;
+ else {
+ PyObject *parentname, *parent;
+ parentname = PyString_FromStringAndSize(name, (subname-name));
+ if (parentname == NULL) {
+ imp_modules_reloading_clear();
+ return NULL;
+ }
+ parent = PyDict_GetItem(modules, parentname);
+ if (parent == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "reload(): parent %.200s not in sys.modules",
+ PyString_AS_STRING(parentname));
+ Py_DECREF(parentname);
+ imp_modules_reloading_clear();
+ return NULL;
+ }
+ Py_DECREF(parentname);
+ subname++;
+ path = PyObject_GetAttrString(parent, "__path__");
+ if (path == NULL)
+ PyErr_Clear();
+ }
+ buf = PyMem_MALLOC(MAXPATHLEN+1);
+ if (buf == NULL) {
+ Py_XDECREF(path);
+ return PyErr_NoMemory();
+ }
+ buf[0] = '\0';
+ fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader);
+ Py_XDECREF(path);
+
+ if (fdp == NULL) {
+ Py_XDECREF(loader);
+ imp_modules_reloading_clear();
+ PyMem_FREE(buf);
+ return NULL;
+ }
+
+ newm = load_module(name, fp, buf, fdp->type, loader);
+ Py_XDECREF(loader);
+
+ if (fp)
+ fclose(fp);
+ if (newm == NULL) {
+ /* load_module probably removed name from modules because of
+ * the error. Put back the original module object. We're
+ * going to return NULL in this case regardless of whether
+ * replacing name succeeds, so the return value is ignored.
+ */
+ PyDict_SetItemString(modules, name, m);
+ }
+ imp_modules_reloading_clear();
+ PyMem_FREE(buf);
+ return newm;
+}
+
+
+/* Higher-level import emulator which emulates the "import" statement
+ more accurately -- it invokes the __import__() function from the
+ builtins of the current globals. This means that the import is
+ done using whatever import hooks are installed in the current
+ environment, e.g. by "rexec".
+ A dummy list ["__doc__"] is passed as the 4th argument so that
+ e.g. PyImport_Import(PyString_FromString("win32com.client.gencache"))
+ will return <module "gencache"> instead of <module "win32com">. */
+
+PyObject *
+PyImport_Import(PyObject *module_name)
+{
+ static PyObject *silly_list = NULL;
+ static PyObject *builtins_str = NULL;
+ static PyObject *import_str = NULL;
+ PyObject *globals = NULL;
+ PyObject *import = NULL;
+ PyObject *builtins = NULL;
+ PyObject *r = NULL;
+
+ /* Initialize constant string objects */
+ if (silly_list == NULL) {
+ import_str = PyString_InternFromString("__import__");
+ if (import_str == NULL)
+ return NULL;
+ builtins_str = PyString_InternFromString("__builtins__");
+ if (builtins_str == NULL)
+ return NULL;
+ silly_list = Py_BuildValue("[s]", "__doc__");
+ if (silly_list == NULL)
+ return NULL;
+ }
+
+ /* Get the builtins from current globals */
+ globals = PyEval_GetGlobals();
+ if (globals != NULL) {
+ Py_INCREF(globals);
+ builtins = PyObject_GetItem(globals, builtins_str);
+ if (builtins == NULL)
+ goto err;
+ }
+ else {
+ /* No globals -- use standard builtins, and fake globals */
+ builtins = PyImport_ImportModuleLevel("__builtin__",
+ NULL, NULL, NULL, 0);
+ if (builtins == NULL)
+ return NULL;
+ globals = Py_BuildValue("{OO}", builtins_str, builtins);
+ if (globals == NULL)
+ goto err;
+ }
+
+ /* Get the __import__ function from the builtins */
+ if (PyDict_Check(builtins)) {
+ import = PyObject_GetItem(builtins, import_str);
+ if (import == NULL)
+ PyErr_SetObject(PyExc_KeyError, import_str);
+ }
+ else
+ import = PyObject_GetAttr(builtins, import_str);
+ if (import == NULL)
+ goto err;
+
+ /* Call the __import__ function with the proper argument list
+ * Always use absolute import here. */
+ r = PyObject_CallFunction(import, "OOOOi", module_name, globals,
+ globals, silly_list, 0, NULL);
+
+ err:
+ Py_XDECREF(globals);
+ Py_XDECREF(builtins);
+ Py_XDECREF(import);
+
+ return r;
+}
+
+
+/* Module 'imp' provides Python access to the primitives used for
+ importing modules.
+*/
+
+static PyObject *
+imp_get_magic(PyObject *self, PyObject *noargs)
+{
+ char buf[4];
+
+ buf[0] = (char) ((pyc_magic >> 0) & 0xff);
+ buf[1] = (char) ((pyc_magic >> 8) & 0xff);
+ buf[2] = (char) ((pyc_magic >> 16) & 0xff);
+ buf[3] = (char) ((pyc_magic >> 24) & 0xff);
+
+ return PyString_FromStringAndSize(buf, 4);
+}
+
+static PyObject *
+imp_get_suffixes(PyObject *self, PyObject *noargs)
+{
+ PyObject *list;
+ struct filedescr *fdp;
+
+ list = PyList_New(0);
+ if (list == NULL)
+ return NULL;
+ for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
+ PyObject *item = Py_BuildValue("ssi",
+ fdp->suffix, fdp->mode, fdp->type);
+ if (item == NULL) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ if (PyList_Append(list, item) < 0) {
+ Py_DECREF(list);
+ Py_DECREF(item);
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ return list;
+}
+
+static PyObject *
+call_find_module(char *name, PyObject *path)
+{
+ extern int fclose(FILE *);
+ PyObject *fob, *ret;
+ struct filedescr *fdp;
+ char *pathname;
+ FILE *fp = NULL;
+
+ pathname = PyMem_MALLOC(MAXPATHLEN+1);
+ if (pathname == NULL) {
+ return PyErr_NoMemory();
+ }
+ pathname[0] = '\0';
+ if (path == Py_None)
+ path = NULL;
+ fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL);
+ if (fdp == NULL) {
+ PyMem_FREE(pathname);
+ return NULL;
+ }
+ if (fp != NULL) {
+ fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose);
+ if (fob == NULL) {
+ PyMem_FREE(pathname);
+ return NULL;
+ }
+ }
+ else {
+ fob = Py_None;
+ Py_INCREF(fob);
+ }
+ ret = Py_BuildValue("Os(ssi)",
+ fob, pathname, fdp->suffix, fdp->mode, fdp->type);
+ Py_DECREF(fob);
+ PyMem_FREE(pathname);
+ return ret;
+}
+
+static PyObject *
+imp_find_module(PyObject *self, PyObject *args)
+{
+ char *name;
+ PyObject *path = NULL;
+ if (!PyArg_ParseTuple(args, "s|O:find_module", &name, &path))
+ return NULL;
+ return call_find_module(name, path);
+}
+
+static PyObject *
+imp_init_builtin(PyObject *self, PyObject *args)
+{
+ char *name;
+ int ret;
+ PyObject *m;
+ if (!PyArg_ParseTuple(args, "s:init_builtin", &name))
+ return NULL;
+ ret = init_builtin(name);
+ if (ret < 0)
+ return NULL;
+ if (ret == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ m = PyImport_AddModule(name);
+ Py_XINCREF(m);
+ return m;
+}
+
+static PyObject *
+imp_init_frozen(PyObject *self, PyObject *args)
+{
+ char *name;
+ int ret;
+ PyObject *m;
+ if (!PyArg_ParseTuple(args, "s:init_frozen", &name))
+ return NULL;
+ ret = PyImport_ImportFrozenModule(name);
+ if (ret < 0)
+ return NULL;
+ if (ret == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ m = PyImport_AddModule(name);
+ Py_XINCREF(m);
+ return m;
+}
+
+static PyObject *
+imp_get_frozen_object(PyObject *self, PyObject *args)
+{
+ char *name;
+
+ if (!PyArg_ParseTuple(args, "s:get_frozen_object", &name))
+ return NULL;
+ return get_frozen_object(name);
+}
+
+static PyObject *
+imp_is_builtin(PyObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s:is_builtin", &name))
+ return NULL;
+ return PyInt_FromLong(is_builtin(name));
+}
+
+static PyObject *
+imp_is_frozen(PyObject *self, PyObject *args)
+{
+ char *name;
+ struct _frozen *p;
+ if (!PyArg_ParseTuple(args, "s:is_frozen", &name))
+ return NULL;
+ p = find_frozen(name);
+ return PyBool_FromLong((long) (p == NULL ? 0 : p->size));
+}
+
+static FILE *
+get_file(char *pathname, PyObject *fob, char *mode)
+{
+ FILE *fp;
+ if (fob == NULL) {
+ if (mode[0] == 'U')
+ mode = "r" PY_STDIOTEXTMODE;
+ fp = fopen(pathname, mode);
+ if (fp == NULL)
+ PyErr_SetFromErrno(PyExc_IOError);
+ }
+ else {
+ fp = PyFile_AsFile(fob);
+ if (fp == NULL)
+ PyErr_SetString(PyExc_ValueError,
+ "bad/closed file object");
+ }
+ return fp;
+}
+
+static PyObject *
+imp_load_compiled(PyObject *self, PyObject *args)
+{
+ char *name;
+ char *pathname;
+ PyObject *fob = NULL;
+ PyObject *m;
+ FILE *fp;
+ if (!PyArg_ParseTuple(args, "ss|O!:load_compiled", &name, &pathname,
+ &PyFile_Type, &fob))
+ return NULL;
+ fp = get_file(pathname, fob, "rb");
+ if (fp == NULL)
+ return NULL;
+ m = load_compiled_module(name, pathname, fp);
+ if (fob == NULL)
+ fclose(fp);
+ return m;
+}
+
+#ifdef HAVE_DYNAMIC_LOADING
+
+static PyObject *
+imp_load_dynamic(PyObject *self, PyObject *args)
+{
+ char *name;
+ char *pathname;
+ PyObject *fob = NULL;
+ PyObject *m;
+ FILE *fp = NULL;
+ if (!PyArg_ParseTuple(args, "ss|O!:load_dynamic", &name, &pathname,
+ &PyFile_Type, &fob))
+ return NULL;
+ if (fob) {
+ fp = get_file(pathname, fob, "r");
+ if (fp == NULL)
+ return NULL;
+ }
+ m = _PyImport_LoadDynamicModule(name, pathname, fp);
+ return m;
+}
+
+#endif /* HAVE_DYNAMIC_LOADING */
+
+static PyObject *
+imp_load_source(PyObject *self, PyObject *args)
+{
+ char *name;
+ char *pathname;
+ PyObject *fob = NULL;
+ PyObject *m;
+ FILE *fp;
+ if (!PyArg_ParseTuple(args, "ss|O!:load_source", &name, &pathname,
+ &PyFile_Type, &fob))
+ return NULL;
+ fp = get_file(pathname, fob, "r");
+ if (fp == NULL)
+ return NULL;
+ m = load_source_module(name, pathname, fp);
+ if (fob == NULL)
+ fclose(fp);
+ return m;
+}
+
+static PyObject *
+imp_load_module(PyObject *self, PyObject *args)
+{
+ char *name;
+ PyObject *fob;
+ char *pathname;
+ char *suffix; /* Unused */
+ char *mode;
+ int type;
+ FILE *fp;
+
+ if (!PyArg_ParseTuple(args, "sOs(ssi):load_module",
+ &name, &fob, &pathname,
+ &suffix, &mode, &type))
+ return NULL;
+ if (*mode) {
+ /* Mode must start with 'r' or 'U' and must not contain '+'.
+ Implicit in this test is the assumption that the mode
+ may contain other modifiers like 'b' or 't'. */
+
+ if (!(*mode == 'r' || *mode == 'U') || strchr(mode, '+')) {
+ PyErr_Format(PyExc_ValueError,
+ "invalid file open mode %.200s", mode);
+ return NULL;
+ }
+ }
+ if (fob == Py_None)
+ fp = NULL;
+ else {
+ if (!PyFile_Check(fob)) {
+ PyErr_SetString(PyExc_ValueError,
+ "load_module arg#2 should be a file or None");
+ return NULL;
+ }
+ fp = get_file(pathname, fob, mode);
+ if (fp == NULL)
+ return NULL;
+ }
+ return load_module(name, fp, pathname, type, NULL);
+}
+
+static PyObject *
+imp_load_package(PyObject *self, PyObject *args)
+{
+ char *name;
+ char *pathname;
+ if (!PyArg_ParseTuple(args, "ss:load_package", &name, &pathname))
+ return NULL;
+ return load_package(name, pathname);
+}
+
+static PyObject *
+imp_new_module(PyObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s:new_module", &name))
+ return NULL;
+ return PyModule_New(name);
+}
+
+static PyObject *
+imp_reload(PyObject *self, PyObject *v)
+{
+ return PyImport_ReloadModule(v);
+}
+
+
+/* Doc strings */
+
+PyDoc_STRVAR(doc_imp,
+"This module provides the components needed to build your own\n\
+__import__ function. Undocumented functions are obsolete.");
+
+PyDoc_STRVAR(doc_reload,
+"reload(module) -> module\n\
+\n\
+Reload the module. The module must have been successfully imported before.");
+
+PyDoc_STRVAR(doc_find_module,
+"find_module(name, [path]) -> (file, filename, (suffix, mode, type))\n\
+Search for a module. If path is omitted or None, search for a\n\
+built-in, frozen or special module and continue search in sys.path.\n\
+The module name cannot contain '.'; to search for a submodule of a\n\
+package, pass the submodule name and the package's __path__.");
+
+PyDoc_STRVAR(doc_load_module,
+"load_module(name, file, filename, (suffix, mode, type)) -> module\n\
+Load a module, given information returned by find_module().\n\
+The module name must include the full package name, if any.");
+
+PyDoc_STRVAR(doc_get_magic,
+"get_magic() -> string\n\
+Return the magic number for .pyc or .pyo files.");
+
+PyDoc_STRVAR(doc_get_suffixes,
+"get_suffixes() -> [(suffix, mode, type), ...]\n\
+Return a list of (suffix, mode, type) tuples describing the files\n\
+that find_module() looks for.");
+
+PyDoc_STRVAR(doc_new_module,
+"new_module(name) -> module\n\
+Create a new module. Do not enter it in sys.modules.\n\
+The module name must include the full package name, if any.");
+
+PyDoc_STRVAR(doc_lock_held,
+"lock_held() -> boolean\n\
+Return True if the import lock is currently held, else False.\n\
+On platforms without threads, return False.");
+
+PyDoc_STRVAR(doc_acquire_lock,
+"acquire_lock() -> None\n\
+Acquires the interpreter's import lock for the current thread.\n\
+This lock should be used by import hooks to ensure thread-safety\n\
+when importing modules.\n\
+On platforms without threads, this function does nothing.");
+
+PyDoc_STRVAR(doc_release_lock,
+"release_lock() -> None\n\
+Release the interpreter's import lock.\n\
+On platforms without threads, this function does nothing.");
+
+static PyMethodDef imp_methods[] = {
+ {"reload", imp_reload, METH_O, doc_reload},
+ {"find_module", imp_find_module, METH_VARARGS, doc_find_module},
+ {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic},
+ {"get_suffixes", imp_get_suffixes, METH_NOARGS, doc_get_suffixes},
+ {"load_module", imp_load_module, METH_VARARGS, doc_load_module},
+ {"new_module", imp_new_module, METH_VARARGS, doc_new_module},
+ {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held},
+ {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock},
+ {"release_lock", imp_release_lock, METH_NOARGS, doc_release_lock},
+ /* The rest are obsolete */
+ {"get_frozen_object", imp_get_frozen_object, METH_VARARGS},
+ {"init_builtin", imp_init_builtin, METH_VARARGS},
+ {"init_frozen", imp_init_frozen, METH_VARARGS},
+ {"is_builtin", imp_is_builtin, METH_VARARGS},
+ {"is_frozen", imp_is_frozen, METH_VARARGS},
+ {"load_compiled", imp_load_compiled, METH_VARARGS},
+#ifdef HAVE_DYNAMIC_LOADING
+ {"load_dynamic", imp_load_dynamic, METH_VARARGS},
+#endif
+ {"load_package", imp_load_package, METH_VARARGS},
+ {"load_source", imp_load_source, METH_VARARGS},
+ {NULL, NULL} /* sentinel */
+};
+
+static int
+setint(PyObject *d, char *name, int value)
+{
+ PyObject *v;
+ int err;
+
+ v = PyInt_FromLong((long)value);
+ err = PyDict_SetItemString(d, name, v);
+ Py_XDECREF(v);
+ return err;
+}
+
+typedef struct {
+ PyObject_HEAD
+} NullImporter;
+
+static int
+NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds)
+{
+ char *path;
+ Py_ssize_t pathlen;
+
+ if (!_PyArg_NoKeywords("NullImporter()", kwds))
+ return -1;
+
+ if (!PyArg_ParseTuple(args, "s:NullImporter",
+ &path))
+ return -1;
+
+ pathlen = strlen(path);
+ if (pathlen == 0) {
+ PyErr_SetString(PyExc_ImportError, "empty pathname");
+ return -1;
+ } else {
+ if(isdir(path)) {
+ PyErr_SetString(PyExc_ImportError,
+ "existing directory");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static PyObject *
+NullImporter_find_module(NullImporter *self, PyObject *args)
+{
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef NullImporter_methods[] = {
+ {"find_module", (PyCFunction)NullImporter_find_module, METH_VARARGS,
+ "Always return None"
+ },
+ {NULL} /* Sentinel */
+};
+
+
+PyTypeObject PyNullImporter_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "imp.NullImporter", /*tp_name*/
+ sizeof(NullImporter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "Null importer object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NullImporter_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)NullImporter_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
+
+
+PyMODINIT_FUNC
+initimp(void)
+{
+ PyObject *m, *d;
+
+ if (PyType_Ready(&PyNullImporter_Type) < 0)
+ goto failure;
+
+ m = Py_InitModule4("imp", imp_methods, doc_imp,
+ NULL, PYTHON_API_VERSION);
+ if (m == NULL)
+ goto failure;
+ d = PyModule_GetDict(m);
+ if (d == NULL)
+ goto failure;
+
+ if (setint(d, "SEARCH_ERROR", SEARCH_ERROR) < 0) goto failure;
+ if (setint(d, "PY_SOURCE", PY_SOURCE) < 0) goto failure;
+ if (setint(d, "PY_COMPILED", PY_COMPILED) < 0) goto failure;
+ if (setint(d, "C_EXTENSION", C_EXTENSION) < 0) goto failure;
+ if (setint(d, "PY_RESOURCE", PY_RESOURCE) < 0) goto failure;
+ if (setint(d, "PKG_DIRECTORY", PKG_DIRECTORY) < 0) goto failure;
+ if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure;
+ if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure;
+ if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure;
+ if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure;
+
+ Py_INCREF(&PyNullImporter_Type);
+ PyModule_AddObject(m, "NullImporter", (PyObject *)&PyNullImporter_Type);
+ failure:
+ ;
+}
+
+
+/* API for embedding applications that want to add their own entries
+ to the table of built-in modules. This should normally be called
+ *before* Py_Initialize(). When the table resize fails, -1 is
+ returned and the existing table is unchanged.
+
+ After a similar function by Just van Rossum. */
+
+int
+PyImport_ExtendInittab(struct _inittab *newtab)
+{
+ static struct _inittab *our_copy = NULL;
+ struct _inittab *p;
+ int i, n;
+
+ /* Count the number of entries in both tables */
+ for (n = 0; newtab[n].name != NULL; n++)
+ ;
+ if (n == 0)
+ return 0; /* Nothing to do */
+ for (i = 0; PyImport_Inittab[i].name != NULL; i++)
+ ;
+
+ /* Allocate new memory for the combined table */
+ p = our_copy;
+ PyMem_RESIZE(p, struct _inittab, i+n+1);
+ if (p == NULL)
+ return -1;
+
+ /* Copy the tables into the new memory */
+ if (our_copy != PyImport_Inittab)
+ memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab));
+ PyImport_Inittab = our_copy = p;
+ memcpy(p+i, newtab, (n+1) * sizeof(struct _inittab));
+
+ return 0;
+}
+
+/* Shorthand to add a single entry given a name and a function */
+
+int
+PyImport_AppendInittab(const char *name, void (*initfunc)(void))
+{
+ struct _inittab newtab[2];
+
+ memset(newtab, '\0', sizeof newtab);
+
+ newtab[0].name = (char *)name;
+ newtab[0].initfunc = initfunc;
+
+ return PyImport_ExtendInittab(newtab);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/tools/python/src/Python/importdl.c b/contrib/tools/python/src/Python/importdl.c
new file mode 100644
index 0000000000..14c9be87d3
--- /dev/null
+++ b/contrib/tools/python/src/Python/importdl.c
@@ -0,0 +1,78 @@
+
+/* Support for dynamic loading of extension modules */
+
+#include "Python.h"
+
+/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is
+ supported on this platform. configure will then compile and link in one
+ of the dynload_*.c files, as appropriate. We will call a function in
+ those modules to get a function pointer to the module's init function.
+*/
+#ifdef HAVE_DYNAMIC_LOADING
+
+#include "importdl.h"
+
+extern dl_funcptr _PyImport_GetDynLoadFunc(const char *name,
+ const char *shortname,
+ const char *pathname, FILE *fp);
+
+
+
+PyObject *
+_PyImport_LoadDynamicModule(char *name, char *pathname, FILE *fp)
+{
+ PyObject *m;
+ char *lastdot, *shortname, *packagecontext, *oldcontext;
+ dl_funcptr p;
+
+ if ((m = _PyImport_FindExtension(name, pathname)) != NULL) {
+ Py_INCREF(m);
+ return m;
+ }
+ lastdot = strrchr(name, '.');
+ if (lastdot == NULL) {
+ packagecontext = NULL;
+ shortname = name;
+ }
+ else {
+ packagecontext = name;
+ shortname = lastdot+1;
+ }
+
+ p = _PyImport_GetDynLoadFunc(name, shortname, pathname, fp);
+ if (PyErr_Occurred())
+ return NULL;
+ if (p == NULL) {
+ PyErr_Format(PyExc_ImportError,
+ "dynamic module does not define init function (init%.200s)",
+ shortname);
+ return NULL;
+ }
+ oldcontext = _Py_PackageContext;
+ _Py_PackageContext = packagecontext;
+ (*p)();
+ _Py_PackageContext = oldcontext;
+ if (PyErr_Occurred())
+ return NULL;
+
+ m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
+ if (m == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "dynamic module not initialized properly");
+ return NULL;
+ }
+ /* Remember the filename as the __file__ attribute */
+ if (PyModule_AddStringConstant(m, "__file__", pathname) < 0)
+ PyErr_Clear(); /* Not important enough to report */
+
+ if (_PyImport_FixupExtension(name, pathname) == NULL)
+ return NULL;
+ if (Py_VerboseFlag)
+ PySys_WriteStderr(
+ "import %s # dynamically loaded from %s\n",
+ name, pathname);
+ Py_INCREF(m);
+ return m;
+}
+
+#endif /* HAVE_DYNAMIC_LOADING */
diff --git a/contrib/tools/python/src/Python/importdl.h b/contrib/tools/python/src/Python/importdl.h
new file mode 100644
index 0000000000..b4d21be6f0
--- /dev/null
+++ b/contrib/tools/python/src/Python/importdl.h
@@ -0,0 +1,53 @@
+#ifndef Py_IMPORTDL_H
+#define Py_IMPORTDL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Definitions for dynamic loading of extension modules */
+enum filetype {
+ SEARCH_ERROR,
+ PY_SOURCE,
+ PY_COMPILED,
+ C_EXTENSION,
+ PY_RESOURCE, /* Mac only */
+ PKG_DIRECTORY,
+ C_BUILTIN,
+ PY_FROZEN,
+ PY_CODERESOURCE, /* Mac only */
+ IMP_HOOK
+};
+
+struct filedescr {
+ char *suffix;
+ char *mode;
+ enum filetype type;
+};
+extern struct filedescr * _PyImport_Filetab;
+extern const struct filedescr _PyImport_DynLoadFiletab[];
+
+extern PyObject *_PyImport_LoadDynamicModule(char *name, char *pathname,
+ FILE *);
+
+/* Max length of module suffix searched for -- accommodates "module.slb" */
+#define MAXSUFFIXSIZE 12
+
+#ifdef MS_WINDOWS
+#include <windows.h>
+typedef FARPROC dl_funcptr;
+#else
+#if defined(PYOS_OS2) && !defined(PYCC_GCC)
+#include <os2def.h>
+typedef int (* APIENTRY dl_funcptr)();
+#else
+typedef void (*dl_funcptr)(void);
+#endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_IMPORTDL_H */
diff --git a/contrib/tools/python/src/Python/marshal.c b/contrib/tools/python/src/Python/marshal.c
new file mode 100644
index 0000000000..f55599bdb0
--- /dev/null
+++ b/contrib/tools/python/src/Python/marshal.c
@@ -0,0 +1,1423 @@
+
+/* Write Python objects to files and read them back.
+ This is intended for writing and reading compiled Python code only;
+ a true persistent storage facility would be much harder, since
+ it would have to take circular links and sharing into account. */
+
+#define PY_SSIZE_T_CLEAN
+
+#include "Python.h"
+#include "longintrepr.h"
+#include "code.h"
+#include "marshal.h"
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+/* High water mark to determine when the marshalled object is dangerously deep
+ * and risks coring the interpreter. When the object stack gets this deep,
+ * raise an exception instead of continuing.
+ * On Windows debug builds, reduce this value.
+ */
+#if defined(MS_WINDOWS) && defined(_DEBUG)
+#define MAX_MARSHAL_STACK_DEPTH 1000
+#else
+#define MAX_MARSHAL_STACK_DEPTH 2000
+#endif
+
+#define TYPE_NULL '0'
+#define TYPE_NONE 'N'
+#define TYPE_FALSE 'F'
+#define TYPE_TRUE 'T'
+#define TYPE_STOPITER 'S'
+#define TYPE_ELLIPSIS '.'
+#define TYPE_INT 'i'
+#define TYPE_INT64 'I'
+#define TYPE_FLOAT 'f'
+#define TYPE_BINARY_FLOAT 'g'
+#define TYPE_COMPLEX 'x'
+#define TYPE_BINARY_COMPLEX 'y'
+#define TYPE_LONG 'l'
+#define TYPE_STRING 's'
+#define TYPE_INTERNED 't'
+#define TYPE_STRINGREF 'R'
+#define TYPE_TUPLE '('
+#define TYPE_LIST '['
+#define TYPE_DICT '{'
+#define TYPE_CODE 'c'
+#define TYPE_UNICODE 'u'
+#define TYPE_UNKNOWN '?'
+#define TYPE_SET '<'
+#define TYPE_FROZENSET '>'
+
+#define WFERR_OK 0
+#define WFERR_UNMARSHALLABLE 1
+#define WFERR_NESTEDTOODEEP 2
+#define WFERR_NOMEMORY 3
+
+typedef struct {
+ FILE *fp;
+ int error; /* see WFERR_* values */
+ int depth;
+ /* If fp == NULL, the following are valid: */
+ PyObject *str;
+ char *ptr;
+ char *end;
+ PyObject *strings; /* dict on marshal, list on unmarshal */
+ int version;
+} WFILE;
+
+#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \
+ else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \
+ else w_more(c, p)
+
+static void
+w_more(int c, WFILE *p)
+{
+ Py_ssize_t size, newsize;
+ if (p->str == NULL)
+ return; /* An error already occurred */
+ size = PyString_Size(p->str);
+ newsize = size + size + 1024;
+ if (newsize > 32*1024*1024) {
+ newsize = size + (size >> 3); /* 12.5% overallocation */
+ }
+ if (_PyString_Resize(&p->str, newsize) != 0) {
+ p->ptr = p->end = NULL;
+ }
+ else {
+ p->ptr = PyString_AS_STRING((PyStringObject *)p->str) + size;
+ p->end =
+ PyString_AS_STRING((PyStringObject *)p->str) + newsize;
+ *p->ptr++ = Py_SAFE_DOWNCAST(c, int, char);
+ }
+}
+
+static void
+w_string(const char *s, Py_ssize_t n, WFILE *p)
+{
+ if (p->fp != NULL) {
+ fwrite(s, 1, n, p->fp);
+ }
+ else {
+ while (--n >= 0) {
+ w_byte(*s, p);
+ s++;
+ }
+ }
+}
+
+static void
+w_short(int x, WFILE *p)
+{
+ w_byte((char)( x & 0xff), p);
+ w_byte((char)((x>> 8) & 0xff), p);
+}
+
+static void
+w_long(long x, WFILE *p)
+{
+ w_byte((char)( x & 0xff), p);
+ w_byte((char)((x>> 8) & 0xff), p);
+ w_byte((char)((x>>16) & 0xff), p);
+ w_byte((char)((x>>24) & 0xff), p);
+}
+
+#if SIZEOF_LONG > 4
+static void
+w_long64(long x, WFILE *p)
+{
+ w_long(x, p);
+ w_long(x>>32, p);
+}
+#endif
+
+#define SIZE32_MAX 0x7FFFFFFF
+
+#if SIZEOF_SIZE_T > 4
+# define W_SIZE(n, p) do { \
+ if ((n) > SIZE32_MAX) { \
+ (p)->depth--; \
+ (p)->error = WFERR_UNMARSHALLABLE; \
+ return; \
+ } \
+ w_long((long)(n), p); \
+ } while(0)
+#else
+# define W_SIZE w_long
+#endif
+
+static void
+w_pstring(const char *s, Py_ssize_t n, WFILE *p)
+{
+ W_SIZE(n, p);
+ w_string(s, n, p);
+}
+
+/* We assume that Python longs are stored internally in base some power of
+ 2**15; for the sake of portability we'll always read and write them in base
+ exactly 2**15. */
+
+#define PyLong_MARSHAL_SHIFT 15
+#define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT)
+#define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1)
+#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0
+#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT"
+#endif
+#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT)
+
+static void
+w_PyLong(const PyLongObject *ob, WFILE *p)
+{
+ Py_ssize_t i, j, n, l;
+ digit d;
+
+ w_byte(TYPE_LONG, p);
+ if (Py_SIZE(ob) == 0) {
+ w_long((long)0, p);
+ return;
+ }
+
+ /* set l to number of base PyLong_MARSHAL_BASE digits */
+ n = ABS(Py_SIZE(ob));
+ l = (n-1) * PyLong_MARSHAL_RATIO;
+ d = ob->ob_digit[n-1];
+ assert(d != 0); /* a PyLong is always normalized */
+ do {
+ d >>= PyLong_MARSHAL_SHIFT;
+ l++;
+ } while (d != 0);
+ if (l > SIZE32_MAX) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p);
+
+ for (i=0; i < n-1; i++) {
+ d = ob->ob_digit[i];
+ for (j=0; j < PyLong_MARSHAL_RATIO; j++) {
+ w_short(d & PyLong_MARSHAL_MASK, p);
+ d >>= PyLong_MARSHAL_SHIFT;
+ }
+ assert (d == 0);
+ }
+ d = ob->ob_digit[n-1];
+ do {
+ w_short(d & PyLong_MARSHAL_MASK, p);
+ d >>= PyLong_MARSHAL_SHIFT;
+ } while (d != 0);
+}
+
+static void
+w_object(PyObject *v, WFILE *p)
+{
+ Py_ssize_t i, n;
+
+ p->depth++;
+
+ if (p->depth > MAX_MARSHAL_STACK_DEPTH) {
+ p->error = WFERR_NESTEDTOODEEP;
+ }
+ else if (v == NULL) {
+ w_byte(TYPE_NULL, p);
+ }
+ else if (v == Py_None) {
+ w_byte(TYPE_NONE, p);
+ }
+ else if (v == PyExc_StopIteration) {
+ w_byte(TYPE_STOPITER, p);
+ }
+ else if (v == Py_Ellipsis) {
+ w_byte(TYPE_ELLIPSIS, p);
+ }
+ else if (v == Py_False) {
+ w_byte(TYPE_FALSE, p);
+ }
+ else if (v == Py_True) {
+ w_byte(TYPE_TRUE, p);
+ }
+ else if (PyInt_CheckExact(v)) {
+ long x = PyInt_AS_LONG((PyIntObject *)v);
+#if SIZEOF_LONG > 4
+ long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31);
+ if (y && y != -1) {
+ w_byte(TYPE_INT64, p);
+ w_long64(x, p);
+ }
+ else
+#endif
+ {
+ w_byte(TYPE_INT, p);
+ w_long(x, p);
+ }
+ }
+ else if (PyLong_CheckExact(v)) {
+ PyLongObject *ob = (PyLongObject *)v;
+ w_PyLong(ob, p);
+ }
+ else if (PyFloat_CheckExact(v)) {
+ if (p->version > 1) {
+ unsigned char buf[8];
+ if (_PyFloat_Pack8(PyFloat_AsDouble(v),
+ buf, 1) < 0) {
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_byte(TYPE_BINARY_FLOAT, p);
+ w_string((char*)buf, 8, p);
+ }
+ else {
+ char *buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
+ 'g', 17, 0, NULL);
+ if (!buf) {
+ p->error = WFERR_NOMEMORY;
+ return;
+ }
+ n = strlen(buf);
+ w_byte(TYPE_FLOAT, p);
+ w_byte((int)n, p);
+ w_string(buf, n, p);
+ PyMem_Free(buf);
+ }
+ }
+#ifndef WITHOUT_COMPLEX
+ else if (PyComplex_CheckExact(v)) {
+ if (p->version > 1) {
+ unsigned char buf[8];
+ if (_PyFloat_Pack8(PyComplex_RealAsDouble(v),
+ buf, 1) < 0) {
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_byte(TYPE_BINARY_COMPLEX, p);
+ w_string((char*)buf, 8, p);
+ if (_PyFloat_Pack8(PyComplex_ImagAsDouble(v),
+ buf, 1) < 0) {
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_string((char*)buf, 8, p);
+ }
+ else {
+ char *buf;
+ w_byte(TYPE_COMPLEX, p);
+ buf = PyOS_double_to_string(PyComplex_RealAsDouble(v),
+ 'g', 17, 0, NULL);
+ if (!buf) {
+ p->error = WFERR_NOMEMORY;
+ return;
+ }
+ n = strlen(buf);
+ w_byte((int)n, p);
+ w_string(buf, n, p);
+ PyMem_Free(buf);
+ buf = PyOS_double_to_string(PyComplex_ImagAsDouble(v),
+ 'g', 17, 0, NULL);
+ if (!buf) {
+ p->error = WFERR_NOMEMORY;
+ return;
+ }
+ n = strlen(buf);
+ w_byte((int)n, p);
+ w_string(buf, n, p);
+ PyMem_Free(buf);
+ }
+ }
+#endif
+ else if (PyString_CheckExact(v)) {
+ if (p->strings && PyString_CHECK_INTERNED(v)) {
+ PyObject *o = PyDict_GetItem(p->strings, v);
+ if (o) {
+ long w = PyInt_AsLong(o);
+ w_byte(TYPE_STRINGREF, p);
+ w_long(w, p);
+ goto exit;
+ }
+ else {
+ int ok;
+ o = PyInt_FromSsize_t(PyDict_Size(p->strings));
+ ok = o &&
+ PyDict_SetItem(p->strings, v, o) >= 0;
+ Py_XDECREF(o);
+ if (!ok) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_byte(TYPE_INTERNED, p);
+ }
+ }
+ else {
+ w_byte(TYPE_STRING, p);
+ }
+ w_pstring(PyBytes_AS_STRING(v), PyString_GET_SIZE(v), p);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_CheckExact(v)) {
+ PyObject *utf8;
+ utf8 = PyUnicode_AsUTF8String(v);
+ if (utf8 == NULL) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ w_byte(TYPE_UNICODE, p);
+ w_pstring(PyString_AS_STRING(utf8), PyString_GET_SIZE(utf8), p);
+ Py_DECREF(utf8);
+ }
+#endif
+ else if (PyTuple_CheckExact(v)) {
+ w_byte(TYPE_TUPLE, p);
+ n = PyTuple_Size(v);
+ W_SIZE(n, p);
+ for (i = 0; i < n; i++) {
+ w_object(PyTuple_GET_ITEM(v, i), p);
+ }
+ }
+ else if (PyList_CheckExact(v)) {
+ w_byte(TYPE_LIST, p);
+ n = PyList_GET_SIZE(v);
+ W_SIZE(n, p);
+ for (i = 0; i < n; i++) {
+ w_object(PyList_GET_ITEM(v, i), p);
+ }
+ }
+ else if (PyDict_CheckExact(v)) {
+ Py_ssize_t pos;
+ PyObject *key, *value;
+ w_byte(TYPE_DICT, p);
+ /* This one is NULL object terminated! */
+ pos = 0;
+ while (PyDict_Next(v, &pos, &key, &value)) {
+ w_object(key, p);
+ w_object(value, p);
+ }
+ w_object((PyObject *)NULL, p);
+ }
+ else if (PyAnySet_CheckExact(v)) {
+ PyObject *value, *it;
+
+ if (PyObject_TypeCheck(v, &PySet_Type))
+ w_byte(TYPE_SET, p);
+ else
+ w_byte(TYPE_FROZENSET, p);
+ n = PyObject_Size(v);
+ if (n == -1) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ W_SIZE(n, p);
+ it = PyObject_GetIter(v);
+ if (it == NULL) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ while ((value = PyIter_Next(it)) != NULL) {
+ w_object(value, p);
+ Py_DECREF(value);
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ p->depth--;
+ p->error = WFERR_UNMARSHALLABLE;
+ return;
+ }
+ }
+ else if (PyCode_Check(v)) {
+ PyCodeObject *co = (PyCodeObject *)v;
+ w_byte(TYPE_CODE, p);
+ w_long(co->co_argcount, p);
+ w_long(co->co_nlocals, p);
+ w_long(co->co_stacksize, p);
+ w_long(co->co_flags, p);
+ w_object(co->co_code, p);
+ w_object(co->co_consts, p);
+ w_object(co->co_names, p);
+ w_object(co->co_varnames, p);
+ w_object(co->co_freevars, p);
+ w_object(co->co_cellvars, p);
+ w_object(co->co_filename, p);
+ w_object(co->co_name, p);
+ w_long(co->co_firstlineno, p);
+ w_object(co->co_lnotab, p);
+ }
+ else if (PyObject_CheckReadBuffer(v)) {
+ /* Write unknown buffer-style objects as a string */
+ char *s;
+ PyBufferProcs *pb = v->ob_type->tp_as_buffer;
+ w_byte(TYPE_STRING, p);
+ n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s);
+ w_pstring(s, n, p);
+ }
+ else {
+ w_byte(TYPE_UNKNOWN, p);
+ p->error = WFERR_UNMARSHALLABLE;
+ }
+ exit:
+ p->depth--;
+}
+
+/* version currently has no effect for writing longs. */
+void
+PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
+{
+ WFILE wf;
+ wf.fp = fp;
+ wf.str = NULL;
+ wf.ptr = NULL;
+ wf.end = NULL;
+ wf.error = WFERR_OK;
+ wf.depth = 0;
+ wf.strings = NULL;
+ wf.version = version;
+ w_long(x, &wf);
+}
+
+void
+PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
+{
+ WFILE wf;
+ wf.fp = fp;
+ wf.str = NULL;
+ wf.ptr = NULL;
+ wf.end = NULL;
+ wf.error = WFERR_OK;
+ wf.depth = 0;
+ wf.strings = (version > 0) ? PyDict_New() : NULL;
+ wf.version = version;
+ w_object(x, &wf);
+ Py_XDECREF(wf.strings);
+}
+
+typedef WFILE RFILE; /* Same struct with different invariants */
+
+#define rs_byte(p) (((p)->ptr < (p)->end) ? (unsigned char)*(p)->ptr++ : EOF)
+
+#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p))
+
+static Py_ssize_t
+r_string(char *s, Py_ssize_t n, RFILE *p)
+{
+ if (p->fp != NULL)
+ /* The result fits into int because it must be <=n. */
+ return fread(s, 1, n, p->fp);
+ if (p->end - p->ptr < n)
+ n = p->end - p->ptr;
+ memcpy(s, p->ptr, n);
+ p->ptr += n;
+ return n;
+}
+
+static int
+r_short(RFILE *p)
+{
+ register short x;
+ x = r_byte(p);
+ x |= r_byte(p) << 8;
+ /* Sign-extension, in case short greater than 16 bits */
+ x |= -(x & 0x8000);
+ return x;
+}
+
+static long
+r_long(RFILE *p)
+{
+ register long x;
+ register FILE *fp = p->fp;
+ if (fp) {
+ x = getc(fp);
+ x |= (long)getc(fp) << 8;
+ x |= (long)getc(fp) << 16;
+ x |= (long)getc(fp) << 24;
+ }
+ else {
+ x = rs_byte(p);
+ x |= (long)rs_byte(p) << 8;
+ x |= (long)rs_byte(p) << 16;
+ x |= (long)rs_byte(p) << 24;
+ }
+#if SIZEOF_LONG > 4
+ /* Sign extension for 64-bit machines */
+ x |= -(x & 0x80000000L);
+#endif
+ return x;
+}
+
+/* r_long64 deals with the TYPE_INT64 code. On a machine with
+ sizeof(long) > 4, it returns a Python int object, else a Python long
+ object. Note that w_long64 writes out TYPE_INT if 32 bits is enough,
+ so there's no inefficiency here in returning a PyLong on 32-bit boxes
+ for everything written via TYPE_INT64 (i.e., if an int is written via
+ TYPE_INT64, it *needs* more than 32 bits).
+*/
+static PyObject *
+r_long64(RFILE *p)
+{
+ long lo4 = r_long(p);
+ long hi4 = r_long(p);
+#if SIZEOF_LONG > 4
+ long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL);
+ return PyInt_FromLong(x);
+#else
+ unsigned char buf[8];
+ int one = 1;
+ int is_little_endian = (int)*(char*)&one;
+ if (is_little_endian) {
+ memcpy(buf, &lo4, 4);
+ memcpy(buf+4, &hi4, 4);
+ }
+ else {
+ memcpy(buf, &hi4, 4);
+ memcpy(buf+4, &lo4, 4);
+ }
+ return _PyLong_FromByteArray(buf, 8, is_little_endian, 1);
+#endif
+}
+
+static PyObject *
+r_PyLong(RFILE *p)
+{
+ PyLongObject *ob;
+ long n, size, i;
+ int j, md, shorts_in_top_digit;
+ digit d;
+
+ n = r_long(p);
+ if (n == 0)
+ return (PyObject *)_PyLong_New(0);
+ if (n < -SIZE32_MAX || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError,
+ "bad marshal data (long size out of range)");
+ return NULL;
+ }
+
+ size = 1 + (ABS(n) - 1) / PyLong_MARSHAL_RATIO;
+ shorts_in_top_digit = 1 + (ABS(n) - 1) % PyLong_MARSHAL_RATIO;
+ ob = _PyLong_New(size);
+ if (ob == NULL)
+ return NULL;
+ Py_SIZE(ob) = n > 0 ? size : -size;
+
+ for (i = 0; i < size-1; i++) {
+ d = 0;
+ for (j=0; j < PyLong_MARSHAL_RATIO; j++) {
+ md = r_short(p);
+ if (md < 0 || md > PyLong_MARSHAL_BASE)
+ goto bad_digit;
+ d += (digit)md << j*PyLong_MARSHAL_SHIFT;
+ }
+ ob->ob_digit[i] = d;
+ }
+ d = 0;
+ for (j=0; j < shorts_in_top_digit; j++) {
+ md = r_short(p);
+ if (md < 0 || md > PyLong_MARSHAL_BASE)
+ goto bad_digit;
+ /* topmost marshal digit should be nonzero */
+ if (md == 0 && j == shorts_in_top_digit - 1) {
+ Py_DECREF(ob);
+ PyErr_SetString(PyExc_ValueError,
+ "bad marshal data (unnormalized long data)");
+ return NULL;
+ }
+ d += (digit)md << j*PyLong_MARSHAL_SHIFT;
+ }
+ /* top digit should be nonzero, else the resulting PyLong won't be
+ normalized */
+ ob->ob_digit[size-1] = d;
+ return (PyObject *)ob;
+ bad_digit:
+ Py_DECREF(ob);
+ PyErr_SetString(PyExc_ValueError,
+ "bad marshal data (digit out of range in long)");
+ return NULL;
+}
+
+
+static PyObject *
+r_object(RFILE *p)
+{
+ /* NULL is a valid return value, it does not necessarily means that
+ an exception is set. */
+ PyObject *v, *v2;
+ long i, n;
+ int type = r_byte(p);
+ PyObject *retval;
+
+ p->depth++;
+
+ if (p->depth > MAX_MARSHAL_STACK_DEPTH) {
+ p->depth--;
+ PyErr_SetString(PyExc_ValueError, "recursion limit exceeded");
+ return NULL;
+ }
+
+ switch (type) {
+
+ case EOF:
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+
+ case TYPE_NULL:
+ retval = NULL;
+ break;
+
+ case TYPE_NONE:
+ Py_INCREF(Py_None);
+ retval = Py_None;
+ break;
+
+ case TYPE_STOPITER:
+ Py_INCREF(PyExc_StopIteration);
+ retval = PyExc_StopIteration;
+ break;
+
+ case TYPE_ELLIPSIS:
+ Py_INCREF(Py_Ellipsis);
+ retval = Py_Ellipsis;
+ break;
+
+ case TYPE_FALSE:
+ Py_INCREF(Py_False);
+ retval = Py_False;
+ break;
+
+ case TYPE_TRUE:
+ Py_INCREF(Py_True);
+ retval = Py_True;
+ break;
+
+ case TYPE_INT:
+ retval = PyInt_FromLong(r_long(p));
+ break;
+
+ case TYPE_INT64:
+ retval = r_long64(p);
+ break;
+
+ case TYPE_LONG:
+ retval = r_PyLong(p);
+ break;
+
+ case TYPE_FLOAT:
+ {
+ char buf[256];
+ double dx;
+ n = r_byte(p);
+ if (n == EOF || r_string(buf, n, p) != n) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ buf[n] = '\0';
+ dx = PyOS_string_to_double(buf, NULL, NULL);
+ if (dx == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ retval = PyFloat_FromDouble(dx);
+ break;
+ }
+
+ case TYPE_BINARY_FLOAT:
+ {
+ unsigned char buf[8];
+ double x;
+ if (r_string((char*)buf, 8, p) != 8) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ x = _PyFloat_Unpack8(buf, 1);
+ if (x == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ retval = PyFloat_FromDouble(x);
+ break;
+ }
+
+#ifndef WITHOUT_COMPLEX
+ case TYPE_COMPLEX:
+ {
+ char buf[256];
+ Py_complex c;
+ n = r_byte(p);
+ if (n == EOF || r_string(buf, n, p) != n) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ buf[n] = '\0';
+ c.real = PyOS_string_to_double(buf, NULL, NULL);
+ if (c.real == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ n = r_byte(p);
+ if (n == EOF || r_string(buf, n, p) != n) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ buf[n] = '\0';
+ c.imag = PyOS_string_to_double(buf, NULL, NULL);
+ if (c.imag == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ retval = PyComplex_FromCComplex(c);
+ break;
+ }
+
+ case TYPE_BINARY_COMPLEX:
+ {
+ unsigned char buf[8];
+ Py_complex c;
+ if (r_string((char*)buf, 8, p) != 8) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ c.real = _PyFloat_Unpack8(buf, 1);
+ if (c.real == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ if (r_string((char*)buf, 8, p) != 8) {
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ c.imag = _PyFloat_Unpack8(buf, 1);
+ if (c.imag == -1.0 && PyErr_Occurred()) {
+ retval = NULL;
+ break;
+ }
+ retval = PyComplex_FromCComplex(c);
+ break;
+ }
+#endif
+
+ case TYPE_INTERNED:
+ case TYPE_STRING:
+ n = r_long(p);
+ if (n < 0 || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)");
+ retval = NULL;
+ break;
+ }
+ v = PyString_FromStringAndSize((char *)NULL, n);
+ if (v == NULL) {
+ retval = NULL;
+ break;
+ }
+ if (r_string(PyString_AS_STRING(v), n, p) != n) {
+ Py_DECREF(v);
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ if (type == TYPE_INTERNED) {
+ PyString_InternInPlace(&v);
+ if (PyList_Append(p->strings, v) < 0) {
+ retval = NULL;
+ break;
+ }
+ }
+ retval = v;
+ break;
+
+ case TYPE_STRINGREF:
+ n = r_long(p);
+ if (n < 0 || n >= PyList_GET_SIZE(p->strings)) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (string ref out of range)");
+ retval = NULL;
+ break;
+ }
+ v = PyList_GET_ITEM(p->strings, n);
+ Py_INCREF(v);
+ retval = v;
+ break;
+
+#ifdef Py_USING_UNICODE
+ case TYPE_UNICODE:
+ {
+ char *buffer;
+
+ n = r_long(p);
+ if (n < 0 || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)");
+ retval = NULL;
+ break;
+ }
+ buffer = PyMem_NEW(char, n);
+ if (buffer == NULL) {
+ retval = PyErr_NoMemory();
+ break;
+ }
+ if (r_string(buffer, n, p) != n) {
+ PyMem_DEL(buffer);
+ PyErr_SetString(PyExc_EOFError,
+ "EOF read where object expected");
+ retval = NULL;
+ break;
+ }
+ v = PyUnicode_DecodeUTF8(buffer, n, NULL);
+ PyMem_DEL(buffer);
+ retval = v;
+ break;
+ }
+#endif
+
+ case TYPE_TUPLE:
+ n = r_long(p);
+ if (n < 0 || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)");
+ retval = NULL;
+ break;
+ }
+ v = PyTuple_New(n);
+ if (v == NULL) {
+ retval = NULL;
+ break;
+ }
+ for (i = 0; i < n; i++) {
+ v2 = r_object(p);
+ if ( v2 == NULL ) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "NULL object in marshal data for tuple");
+ Py_DECREF(v);
+ v = NULL;
+ break;
+ }
+ PyTuple_SET_ITEM(v, i, v2);
+ }
+ retval = v;
+ break;
+
+ case TYPE_LIST:
+ n = r_long(p);
+ if (n < 0 || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)");
+ retval = NULL;
+ break;
+ }
+ v = PyList_New(n);
+ if (v == NULL) {
+ retval = NULL;
+ break;
+ }
+ for (i = 0; i < n; i++) {
+ v2 = r_object(p);
+ if ( v2 == NULL ) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "NULL object in marshal data for list");
+ Py_DECREF(v);
+ v = NULL;
+ break;
+ }
+ PyList_SET_ITEM(v, i, v2);
+ }
+ retval = v;
+ break;
+
+ case TYPE_DICT:
+ v = PyDict_New();
+ if (v == NULL) {
+ retval = NULL;
+ break;
+ }
+ for (;;) {
+ PyObject *key, *val;
+ key = r_object(p);
+ if (key == NULL)
+ break;
+ val = r_object(p);
+ if (val != NULL)
+ PyDict_SetItem(v, key, val);
+ Py_DECREF(key);
+ Py_XDECREF(val);
+ }
+ if (PyErr_Occurred()) {
+ Py_DECREF(v);
+ v = NULL;
+ }
+ retval = v;
+ break;
+
+ case TYPE_SET:
+ case TYPE_FROZENSET:
+ n = r_long(p);
+ if (n < 0 || n > SIZE32_MAX) {
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)");
+ retval = NULL;
+ break;
+ }
+ v = (type == TYPE_SET) ? PySet_New(NULL) : PyFrozenSet_New(NULL);
+ if (v == NULL) {
+ retval = NULL;
+ break;
+ }
+ for (i = 0; i < n; i++) {
+ v2 = r_object(p);
+ if ( v2 == NULL ) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "NULL object in marshal data for set");
+ Py_DECREF(v);
+ v = NULL;
+ break;
+ }
+ if (PySet_Add(v, v2) == -1) {
+ Py_DECREF(v);
+ Py_DECREF(v2);
+ v = NULL;
+ break;
+ }
+ Py_DECREF(v2);
+ }
+ retval = v;
+ break;
+
+ case TYPE_CODE:
+ if (PyEval_GetRestricted()) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot unmarshal code objects in "
+ "restricted execution mode");
+ retval = NULL;
+ break;
+ }
+ else {
+ int argcount;
+ int nlocals;
+ int stacksize;
+ int flags;
+ PyObject *code = NULL;
+ PyObject *consts = NULL;
+ PyObject *names = NULL;
+ PyObject *varnames = NULL;
+ PyObject *freevars = NULL;
+ PyObject *cellvars = NULL;
+ PyObject *filename = NULL;
+ PyObject *name = NULL;
+ int firstlineno;
+ PyObject *lnotab = NULL;
+
+ v = NULL;
+
+ /* XXX ignore long->int overflows for now */
+ argcount = (int)r_long(p);
+ nlocals = (int)r_long(p);
+ stacksize = (int)r_long(p);
+ flags = (int)r_long(p);
+ code = r_object(p);
+ if (code == NULL)
+ goto code_error;
+ consts = r_object(p);
+ if (consts == NULL)
+ goto code_error;
+ names = r_object(p);
+ if (names == NULL)
+ goto code_error;
+ varnames = r_object(p);
+ if (varnames == NULL)
+ goto code_error;
+ freevars = r_object(p);
+ if (freevars == NULL)
+ goto code_error;
+ cellvars = r_object(p);
+ if (cellvars == NULL)
+ goto code_error;
+ filename = r_object(p);
+ if (filename == NULL)
+ goto code_error;
+ name = r_object(p);
+ if (name == NULL)
+ goto code_error;
+ firstlineno = (int)r_long(p);
+ lnotab = r_object(p);
+ if (lnotab == NULL)
+ goto code_error;
+
+ v = (PyObject *) PyCode_New(
+ argcount, nlocals, stacksize, flags,
+ code, consts, names, varnames,
+ freevars, cellvars, filename, name,
+ firstlineno, lnotab);
+
+ code_error:
+ Py_XDECREF(code);
+ Py_XDECREF(consts);
+ Py_XDECREF(names);
+ Py_XDECREF(varnames);
+ Py_XDECREF(freevars);
+ Py_XDECREF(cellvars);
+ Py_XDECREF(filename);
+ Py_XDECREF(name);
+ Py_XDECREF(lnotab);
+
+ }
+ retval = v;
+ break;
+
+ default:
+ /* Bogus data got written, which isn't ideal.
+ This will let you keep working and recover. */
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (unknown type code)");
+ retval = NULL;
+ break;
+
+ }
+ p->depth--;
+ return retval;
+}
+
+static PyObject *
+read_object(RFILE *p)
+{
+ PyObject *v;
+ if (PyErr_Occurred()) {
+ fprintf(stderr, "XXX readobject called with exception set\n");
+ return NULL;
+ }
+ v = r_object(p);
+ if (v == NULL && !PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for object");
+ return v;
+}
+
+int
+PyMarshal_ReadShortFromFile(FILE *fp)
+{
+ RFILE rf;
+ assert(fp);
+ rf.fp = fp;
+ rf.strings = NULL;
+ rf.end = rf.ptr = NULL;
+ return r_short(&rf);
+}
+
+long
+PyMarshal_ReadLongFromFile(FILE *fp)
+{
+ RFILE rf;
+ rf.fp = fp;
+ rf.strings = NULL;
+ rf.ptr = rf.end = NULL;
+ return r_long(&rf);
+}
+
+#ifdef HAVE_FSTAT
+/* Return size of file in bytes; < 0 if unknown. */
+static off_t
+getfilesize(FILE *fp)
+{
+ struct stat st;
+ if (fstat(fileno(fp), &st) != 0)
+ return -1;
+ else
+ return st.st_size;
+}
+#endif
+
+/* If we can get the size of the file up-front, and it's reasonably small,
+ * read it in one gulp and delegate to ...FromString() instead. Much quicker
+ * than reading a byte at a time from file; speeds .pyc imports.
+ * CAUTION: since this may read the entire remainder of the file, don't
+ * call it unless you know you're done with the file.
+ */
+PyObject *
+PyMarshal_ReadLastObjectFromFile(FILE *fp)
+{
+/* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */
+#define REASONABLE_FILE_LIMIT (1L << 18)
+#ifdef HAVE_FSTAT
+ off_t filesize;
+ filesize = getfilesize(fp);
+ if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) {
+ char* pBuf = (char *)PyMem_MALLOC(filesize);
+ if (pBuf != NULL) {
+ size_t n = fread(pBuf, 1, (size_t)filesize, fp);
+ PyObject* v = PyMarshal_ReadObjectFromString(pBuf, n);
+ PyMem_FREE(pBuf);
+ return v;
+ }
+
+ }
+#endif
+ /* We don't have fstat, or we do but the file is larger than
+ * REASONABLE_FILE_LIMIT or malloc failed -- read a byte at a time.
+ */
+ return PyMarshal_ReadObjectFromFile(fp);
+
+#undef REASONABLE_FILE_LIMIT
+}
+
+PyObject *
+PyMarshal_ReadObjectFromFile(FILE *fp)
+{
+ RFILE rf;
+ PyObject *result;
+ rf.fp = fp;
+ rf.strings = PyList_New(0);
+ rf.depth = 0;
+ rf.ptr = rf.end = NULL;
+ result = r_object(&rf);
+ Py_DECREF(rf.strings);
+ return result;
+}
+
+PyObject *
+PyMarshal_ReadObjectFromString(char *str, Py_ssize_t len)
+{
+ RFILE rf;
+ PyObject *result;
+ rf.fp = NULL;
+ rf.ptr = str;
+ rf.end = str + len;
+ rf.strings = PyList_New(0);
+ rf.depth = 0;
+ result = r_object(&rf);
+ Py_DECREF(rf.strings);
+ return result;
+}
+
+static void
+set_error(int error)
+{
+ switch (error) {
+ case WFERR_NOMEMORY:
+ PyErr_NoMemory();
+ break;
+ case WFERR_UNMARSHALLABLE:
+ PyErr_SetString(PyExc_ValueError, "unmarshallable object");
+ break;
+ case WFERR_NESTEDTOODEEP:
+ default:
+ PyErr_SetString(PyExc_ValueError,
+ "object too deeply nested to marshal");
+ break;
+ }
+}
+
+PyObject *
+PyMarshal_WriteObjectToString(PyObject *x, int version)
+{
+ WFILE wf;
+ wf.fp = NULL;
+ wf.str = PyString_FromStringAndSize((char *)NULL, 50);
+ if (wf.str == NULL)
+ return NULL;
+ wf.ptr = PyString_AS_STRING((PyStringObject *)wf.str);
+ wf.end = wf.ptr + PyString_Size(wf.str);
+ wf.error = WFERR_OK;
+ wf.depth = 0;
+ wf.version = version;
+ wf.strings = (version > 0) ? PyDict_New() : NULL;
+ w_object(x, &wf);
+ Py_XDECREF(wf.strings);
+ if (wf.str != NULL) {
+ char *base = PyString_AS_STRING((PyStringObject *)wf.str);
+ if (wf.ptr - base > PY_SSIZE_T_MAX) {
+ Py_DECREF(wf.str);
+ PyErr_SetString(PyExc_OverflowError,
+ "too much marshall data for a string");
+ return NULL;
+ }
+ if (_PyString_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base)))
+ return NULL;
+ }
+ if (wf.error != WFERR_OK) {
+ Py_XDECREF(wf.str);
+ set_error(wf.error);
+ return NULL;
+ }
+ return wf.str;
+}
+
+/* And an interface for Python programs... */
+
+static PyObject *
+marshal_dump(PyObject *self, PyObject *args)
+{
+ WFILE wf;
+ PyObject *x;
+ PyObject *f;
+ int version = Py_MARSHAL_VERSION;
+ if (!PyArg_ParseTuple(args, "OO|i:dump", &x, &f, &version))
+ return NULL;
+ if (!PyFile_Check(f)) {
+ PyErr_SetString(PyExc_TypeError,
+ "marshal.dump() 2nd arg must be file");
+ return NULL;
+ }
+ wf.fp = PyFile_AsFile(f);
+ wf.str = NULL;
+ wf.ptr = wf.end = NULL;
+ wf.error = WFERR_OK;
+ wf.depth = 0;
+ wf.strings = (version > 0) ? PyDict_New() : 0;
+ wf.version = version;
+ w_object(x, &wf);
+ Py_XDECREF(wf.strings);
+ if (wf.error != WFERR_OK) {
+ set_error(wf.error);
+ return NULL;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(dump_doc,
+"dump(value, file[, version])\n\
+\n\
+Write the value on the open file. The value must be a supported type.\n\
+The file must be an open file object such as sys.stdout or returned by\n\
+open() or os.popen(). It must be opened in binary mode ('wb' or 'w+b').\n\
+\n\
+If the value has (or contains an object that has) an unsupported type, a\n\
+ValueError exception is raised — but garbage data will also be written\n\
+to the file. The object will not be properly read back by load()\n\
+\n\
+New in version 2.4: The version argument indicates the data format that\n\
+dump should use.");
+
+static PyObject *
+marshal_load(PyObject *self, PyObject *f)
+{
+ RFILE rf;
+ PyObject *result;
+ if (!PyFile_Check(f)) {
+ PyErr_SetString(PyExc_TypeError,
+ "marshal.load() arg must be file");
+ return NULL;
+ }
+ rf.fp = PyFile_AsFile(f);
+ rf.strings = PyList_New(0);
+ rf.depth = 0;
+ result = read_object(&rf);
+ Py_DECREF(rf.strings);
+ return result;
+}
+
+PyDoc_STRVAR(load_doc,
+"load(file)\n\
+\n\
+Read one value from the open file and return it. If no valid value is\n\
+read (e.g. because the data has a different Python version’s\n\
+incompatible marshal format), raise EOFError, ValueError or TypeError.\n\
+The file must be an open file object opened in binary mode ('rb' or\n\
+'r+b').\n\
+\n\
+Note: If an object containing an unsupported type was marshalled with\n\
+dump(), load() will substitute None for the unmarshallable type.");
+
+
+static PyObject *
+marshal_dumps(PyObject *self, PyObject *args)
+{
+ PyObject *x;
+ int version = Py_MARSHAL_VERSION;
+ if (!PyArg_ParseTuple(args, "O|i:dumps", &x, &version))
+ return NULL;
+ return PyMarshal_WriteObjectToString(x, version);
+}
+
+PyDoc_STRVAR(dumps_doc,
+"dumps(value[, version])\n\
+\n\
+Return the string that would be written to a file by dump(value, file).\n\
+The value must be a supported type. Raise a ValueError exception if\n\
+value has (or contains an object that has) an unsupported type.\n\
+\n\
+New in version 2.4: The version argument indicates the data format that\n\
+dumps should use.");
+
+
+static PyObject *
+marshal_loads(PyObject *self, PyObject *args)
+{
+ RFILE rf;
+ char *s;
+ Py_ssize_t n;
+ PyObject* result;
+ if (!PyArg_ParseTuple(args, "s#:loads", &s, &n))
+ return NULL;
+ rf.fp = NULL;
+ rf.ptr = s;
+ rf.end = s + n;
+ rf.strings = PyList_New(0);
+ rf.depth = 0;
+ result = read_object(&rf);
+ Py_DECREF(rf.strings);
+ return result;
+}
+
+PyDoc_STRVAR(loads_doc,
+"loads(string)\n\
+\n\
+Convert the string to a value. If no valid value is found, raise\n\
+EOFError, ValueError or TypeError. Extra characters in the string are\n\
+ignored.");
+
+static PyMethodDef marshal_methods[] = {
+ {"dump", marshal_dump, METH_VARARGS, dump_doc},
+ {"load", marshal_load, METH_O, load_doc},
+ {"dumps", marshal_dumps, METH_VARARGS, dumps_doc},
+ {"loads", marshal_loads, METH_VARARGS, loads_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+PyDoc_STRVAR(marshal_doc,
+"This module contains functions that can read and write Python values in\n\
+a binary format. The format is specific to Python, but independent of\n\
+machine architecture issues.\n\
+\n\
+Not all Python object types are supported; in general, only objects\n\
+whose value is independent from a particular invocation of Python can be\n\
+written and read by this module. The following types are supported:\n\
+None, integers, long integers, floating point numbers, strings, Unicode\n\
+objects, tuples, lists, sets, dictionaries, and code objects, where it\n\
+should be understood that tuples, lists and dictionaries are only\n\
+supported as long as the values contained therein are themselves\n\
+supported; and recursive lists and dictionaries should not be written\n\
+(they will cause infinite loops).\n\
+\n\
+Variables:\n\
+\n\
+version -- indicates the format that the module uses. Version 0 is the\n\
+ historical format, version 1 (added in Python 2.4) shares interned\n\
+ strings and version 2 (added in Python 2.5) uses a binary format for\n\
+ floating point numbers. (New in version 2.4)\n\
+\n\
+Functions:\n\
+\n\
+dump() -- write value to a file\n\
+load() -- read value from a file\n\
+dumps() -- write value to a string\n\
+loads() -- read value from a string");
+
+
+PyMODINIT_FUNC
+PyMarshal_Init(void)
+{
+ PyObject *mod = Py_InitModule3("marshal", marshal_methods,
+ marshal_doc);
+ if (mod == NULL)
+ return;
+ PyModule_AddIntConstant(mod, "version", Py_MARSHAL_VERSION);
+}
diff --git a/contrib/tools/python/src/Python/modsupport.c b/contrib/tools/python/src/Python/modsupport.c
new file mode 100644
index 0000000000..ebe62c360e
--- /dev/null
+++ b/contrib/tools/python/src/Python/modsupport.c
@@ -0,0 +1,670 @@
+
+/* Module support implementation */
+
+#include "Python.h"
+
+#define FLAG_SIZE_T 1
+typedef double va_double;
+
+static PyObject *va_build_value(const char *, va_list, int);
+
+/* Package context -- the full module name for package imports */
+char *_Py_PackageContext = NULL;
+
+/* Py_InitModule4() parameters:
+ - name is the module name
+ - methods is the list of top-level functions
+ - doc is the documentation string
+ - passthrough is passed as self to functions defined in the module
+ - api_version is the value of PYTHON_API_VERSION at the time the
+ module was compiled
+
+ Return value is a borrowed reference to the module object; or NULL
+ if an error occurred (in Python 1.4 and before, errors were fatal).
+ Errors may still leak memory.
+*/
+
+static char api_version_warning[] =
+"Python C API version mismatch for module %.100s:\
+ This Python has API version %d, module %.100s has version %d.";
+
+PyObject *
+Py_InitModule4(const char *name, PyMethodDef *methods, const char *doc,
+ PyObject *passthrough, int module_api_version)
+{
+ PyObject *m, *d, *v, *n;
+ PyMethodDef *ml;
+ PyInterpreterState *interp = PyThreadState_Get()->interp;
+ if (interp->modules == NULL)
+ Py_FatalError("Python import machinery not initialized");
+ if (module_api_version != PYTHON_API_VERSION) {
+ char message[512];
+ PyOS_snprintf(message, sizeof(message),
+ api_version_warning, name,
+ PYTHON_API_VERSION, name,
+ module_api_version);
+ if (PyErr_Warn(PyExc_RuntimeWarning, message))
+ return NULL;
+ }
+ /* Make sure name is fully qualified.
+
+ This is a bit of a hack: when the shared library is loaded,
+ the module name is "package.module", but the module calls
+ Py_InitModule*() with just "module" for the name. The shared
+ library loader squirrels away the true name of the module in
+ _Py_PackageContext, and Py_InitModule*() will substitute this
+ (if the name actually matches).
+ */
+ if (_Py_PackageContext != NULL) {
+ char *p = strrchr(_Py_PackageContext, '.');
+ if (p != NULL && strcmp(name, p+1) == 0) {
+ name = _Py_PackageContext;
+ _Py_PackageContext = NULL;
+ }
+ }
+ if ((m = PyImport_AddModule(name)) == NULL)
+ return NULL;
+ d = PyModule_GetDict(m);
+ if (methods != NULL) {
+ n = PyString_FromString(name);
+ if (n == NULL)
+ return NULL;
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ if ((ml->ml_flags & METH_CLASS) ||
+ (ml->ml_flags & METH_STATIC)) {
+ PyErr_SetString(PyExc_ValueError,
+ "module functions cannot set"
+ " METH_CLASS or METH_STATIC");
+ Py_DECREF(n);
+ return NULL;
+ }
+ v = PyCFunction_NewEx(ml, passthrough, n);
+ if (v == NULL) {
+ Py_DECREF(n);
+ return NULL;
+ }
+ if (PyDict_SetItemString(d, ml->ml_name, v) != 0) {
+ Py_DECREF(v);
+ Py_DECREF(n);
+ return NULL;
+ }
+ Py_DECREF(v);
+ }
+ Py_DECREF(n);
+ }
+ if (doc != NULL) {
+ v = PyString_FromString(doc);
+ if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) {
+ Py_XDECREF(v);
+ return NULL;
+ }
+ Py_DECREF(v);
+ }
+ return m;
+}
+
+
+/* Helper for mkvalue() to scan the length of a format */
+
+static int
+countformat(const char *format, int endchar)
+{
+ int count = 0;
+ int level = 0;
+ while (level > 0 || *format != endchar) {
+ switch (*format) {
+ case '\0':
+ /* Premature end */
+ PyErr_SetString(PyExc_SystemError,
+ "unmatched paren in format");
+ return -1;
+ case '(':
+ case '[':
+ case '{':
+ if (level == 0)
+ count++;
+ level++;
+ break;
+ case ')':
+ case ']':
+ case '}':
+ level--;
+ break;
+ case '#':
+ case '&':
+ case ',':
+ case ':':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 0)
+ count++;
+ }
+ format++;
+ }
+ return count;
+}
+
+
+/* Generic function to create a value -- the inverse of getargs() */
+/* After an original idea and first implementation by Steven Miale */
+
+static PyObject *do_mktuple(const char**, va_list *, int, int, int);
+static PyObject *do_mklist(const char**, va_list *, int, int, int);
+static PyObject *do_mkdict(const char**, va_list *, int, int, int);
+static PyObject *do_mkvalue(const char**, va_list *, int);
+
+
+static void
+do_ignore(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+ PyObject *v;
+ int i;
+ assert(PyErr_Occurred());
+ v = PyTuple_New(n);
+ for (i = 0; i < n; i++) {
+ PyObject *exception, *value, *tb, *w;
+ PyErr_Fetch(&exception, &value, &tb);
+ w = do_mkvalue(p_format, p_va, flags);
+ PyErr_Restore(exception, value, tb);
+ if (w != NULL) {
+ if (v != NULL) {
+ PyTuple_SET_ITEM(v, i, w);
+ }
+ else {
+ Py_DECREF(w);
+ }
+ }
+ }
+ Py_XDECREF(v);
+ if (**p_format != endchar) {
+ PyErr_SetString(PyExc_SystemError,
+ "Unmatched paren in format");
+ return;
+ }
+ if (endchar)
+ ++*p_format;
+}
+
+static PyObject *
+do_mkdict(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+ PyObject *d;
+ int i;
+ if (n < 0)
+ return NULL;
+ if (n % 2) {
+ PyErr_SetString(PyExc_SystemError,
+ "Bad dict format");
+ do_ignore(p_format, p_va, endchar, n, flags);
+ return NULL;
+ }
+ /* Note that we can't bail immediately on error as this will leak
+ refcounts on any 'N' arguments. */
+ if ((d = PyDict_New()) == NULL) {
+ do_ignore(p_format, p_va, endchar, n, flags);
+ return NULL;
+ }
+ for (i = 0; i < n; i+= 2) {
+ PyObject *k, *v;
+
+ k = do_mkvalue(p_format, p_va, flags);
+ if (k == NULL) {
+ do_ignore(p_format, p_va, endchar, n - i - 1, flags);
+ Py_DECREF(d);
+ return NULL;
+ }
+ v = do_mkvalue(p_format, p_va, flags);
+ if (v == NULL || PyDict_SetItem(d, k, v) < 0) {
+ do_ignore(p_format, p_va, endchar, n - i - 2, flags);
+ Py_DECREF(k);
+ Py_XDECREF(v);
+ Py_DECREF(d);
+ return NULL;
+ }
+ Py_DECREF(k);
+ Py_DECREF(v);
+ }
+ if (**p_format != endchar) {
+ Py_DECREF(d);
+ PyErr_SetString(PyExc_SystemError,
+ "Unmatched paren in format");
+ return NULL;
+ }
+ if (endchar)
+ ++*p_format;
+ return d;
+}
+
+static PyObject *
+do_mklist(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+ PyObject *v;
+ int i;
+ if (n < 0)
+ return NULL;
+ /* Note that we can't bail immediately on error as this will leak
+ refcounts on any 'N' arguments. */
+ v = PyList_New(n);
+ if (v == NULL) {
+ do_ignore(p_format, p_va, endchar, n, flags);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ PyObject *w = do_mkvalue(p_format, p_va, flags);
+ if (w == NULL) {
+ do_ignore(p_format, p_va, endchar, n - i - 1, flags);
+ Py_DECREF(v);
+ return NULL;
+ }
+ PyList_SET_ITEM(v, i, w);
+ }
+ if (**p_format != endchar) {
+ Py_DECREF(v);
+ PyErr_SetString(PyExc_SystemError,
+ "Unmatched paren in format");
+ return NULL;
+ }
+ if (endchar)
+ ++*p_format;
+ return v;
+}
+
+#ifdef Py_USING_UNICODE
+static int
+_ustrlen(Py_UNICODE *u)
+{
+ int i = 0;
+ Py_UNICODE *v = u;
+ while (*v != 0) { i++; v++; }
+ return i;
+}
+#endif
+
+static PyObject *
+do_mktuple(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+ PyObject *v;
+ int i;
+ if (n < 0)
+ return NULL;
+ /* Note that we can't bail immediately on error as this will leak
+ refcounts on any 'N' arguments. */
+ if ((v = PyTuple_New(n)) == NULL) {
+ do_ignore(p_format, p_va, endchar, n, flags);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ PyObject *w = do_mkvalue(p_format, p_va, flags);
+ if (w == NULL) {
+ do_ignore(p_format, p_va, endchar, n - i - 1, flags);
+ Py_DECREF(v);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(v, i, w);
+ }
+ if (**p_format != endchar) {
+ Py_DECREF(v);
+ PyErr_SetString(PyExc_SystemError,
+ "Unmatched paren in format");
+ return NULL;
+ }
+ if (endchar)
+ ++*p_format;
+ return v;
+}
+
+static PyObject *
+do_mkvalue(const char **p_format, va_list *p_va, int flags)
+{
+ for (;;) {
+ switch (*(*p_format)++) {
+ case '(':
+ return do_mktuple(p_format, p_va, ')',
+ countformat(*p_format, ')'), flags);
+
+ case '[':
+ return do_mklist(p_format, p_va, ']',
+ countformat(*p_format, ']'), flags);
+
+ case '{':
+ return do_mkdict(p_format, p_va, '}',
+ countformat(*p_format, '}'), flags);
+
+ case 'b':
+ case 'B':
+ case 'h':
+ case 'i':
+ return PyInt_FromLong((long)va_arg(*p_va, int));
+
+ case 'H':
+ return PyInt_FromLong((long)va_arg(*p_va, unsigned int));
+
+ case 'I':
+ {
+ unsigned int n;
+ n = va_arg(*p_va, unsigned int);
+ if (n > (unsigned long)PyInt_GetMax())
+ return PyLong_FromUnsignedLong((unsigned long)n);
+ else
+ return PyInt_FromLong(n);
+ }
+
+ case 'n':
+#if SIZEOF_SIZE_T!=SIZEOF_LONG
+ return PyInt_FromSsize_t(va_arg(*p_va, Py_ssize_t));
+#endif
+ /* Fall through from 'n' to 'l' if Py_ssize_t is long */
+ case 'l':
+ return PyInt_FromLong(va_arg(*p_va, long));
+
+ case 'k':
+ {
+ unsigned long n;
+ n = va_arg(*p_va, unsigned long);
+ if (n > (unsigned long)PyInt_GetMax())
+ return PyLong_FromUnsignedLong(n);
+ else
+ return PyInt_FromLong(n);
+ }
+
+#ifdef HAVE_LONG_LONG
+ case 'L':
+ return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG));
+
+ case 'K':
+ return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG));
+#endif
+#ifdef Py_USING_UNICODE
+ case 'u':
+ {
+ PyObject *v;
+ Py_UNICODE *u = va_arg(*p_va, Py_UNICODE *);
+ Py_ssize_t n;
+ if (**p_format == '#') {
+ ++*p_format;
+ if (flags & FLAG_SIZE_T)
+ n = va_arg(*p_va, Py_ssize_t);
+ else
+ n = va_arg(*p_va, int);
+ }
+ else
+ n = -1;
+ if (u == NULL) {
+ v = Py_None;
+ Py_INCREF(v);
+ }
+ else {
+ if (n < 0)
+ n = _ustrlen(u);
+ v = PyUnicode_FromUnicode(u, n);
+ }
+ return v;
+ }
+#endif
+ case 'f':
+ case 'd':
+ return PyFloat_FromDouble(
+ (double)va_arg(*p_va, va_double));
+
+#ifndef WITHOUT_COMPLEX
+ case 'D':
+ return PyComplex_FromCComplex(
+ *((Py_complex *)va_arg(*p_va, Py_complex *)));
+#endif /* WITHOUT_COMPLEX */
+
+ case 'c':
+ {
+ char p[1];
+ p[0] = (char)va_arg(*p_va, int);
+ return PyString_FromStringAndSize(p, 1);
+ }
+
+ case 's':
+ case 'z':
+ {
+ PyObject *v;
+ char *str = va_arg(*p_va, char *);
+ Py_ssize_t n;
+ if (**p_format == '#') {
+ ++*p_format;
+ if (flags & FLAG_SIZE_T)
+ n = va_arg(*p_va, Py_ssize_t);
+ else
+ n = va_arg(*p_va, int);
+ }
+ else
+ n = -1;
+ if (str == NULL) {
+ v = Py_None;
+ Py_INCREF(v);
+ }
+ else {
+ if (n < 0) {
+ size_t m = strlen(str);
+ if (m > PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "string too long for Python string");
+ return NULL;
+ }
+ n = (Py_ssize_t)m;
+ }
+ v = PyString_FromStringAndSize(str, n);
+ }
+ return v;
+ }
+
+ case 'N':
+ case 'S':
+ case 'O':
+ if (**p_format == '&') {
+ typedef PyObject *(*converter)(void *);
+ converter func = va_arg(*p_va, converter);
+ void *arg = va_arg(*p_va, void *);
+ ++*p_format;
+ return (*func)(arg);
+ }
+ else {
+ PyObject *v;
+ v = va_arg(*p_va, PyObject *);
+ if (v != NULL) {
+ if (*(*p_format - 1) != 'N')
+ Py_INCREF(v);
+ }
+ else if (!PyErr_Occurred())
+ /* If a NULL was passed
+ * because a call that should
+ * have constructed a value
+ * failed, that's OK, and we
+ * pass the error on; but if
+ * no error occurred it's not
+ * clear that the caller knew
+ * what she was doing. */
+ PyErr_SetString(PyExc_SystemError,
+ "NULL object passed to Py_BuildValue");
+ return v;
+ }
+
+ case ':':
+ case ',':
+ case ' ':
+ case '\t':
+ break;
+
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "bad format char passed to Py_BuildValue");
+ return NULL;
+
+ }
+ }
+}
+
+
+PyObject *
+Py_BuildValue(const char *format, ...)
+{
+ va_list va;
+ PyObject* retval;
+ va_start(va, format);
+ retval = va_build_value(format, va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyObject *
+_Py_BuildValue_SizeT(const char *format, ...)
+{
+ va_list va;
+ PyObject* retval;
+ va_start(va, format);
+ retval = va_build_value(format, va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+PyObject *
+Py_VaBuildValue(const char *format, va_list va)
+{
+ return va_build_value(format, va, 0);
+}
+
+PyObject *
+_Py_VaBuildValue_SizeT(const char *format, va_list va)
+{
+ return va_build_value(format, va, FLAG_SIZE_T);
+}
+
+static PyObject *
+va_build_value(const char *format, va_list va, int flags)
+{
+ const char *f = format;
+ int n = countformat(f, '\0');
+ va_list lva;
+
+#ifdef VA_LIST_IS_ARRAY
+ memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(lva, va);
+#else
+ lva = va;
+#endif
+#endif
+
+ if (n < 0)
+ return NULL;
+ if (n == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (n == 1)
+ return do_mkvalue(&f, &lva, flags);
+ return do_mktuple(&f, &lva, '\0', n, flags);
+}
+
+
+PyObject *
+PyEval_CallFunction(PyObject *obj, const char *format, ...)
+{
+ va_list vargs;
+ PyObject *args;
+ PyObject *res;
+
+ va_start(vargs, format);
+
+ args = Py_VaBuildValue(format, vargs);
+ va_end(vargs);
+
+ if (args == NULL)
+ return NULL;
+
+ res = PyEval_CallObject(obj, args);
+ Py_DECREF(args);
+
+ return res;
+}
+
+
+PyObject *
+PyEval_CallMethod(PyObject *obj, const char *methodname, const char *format, ...)
+{
+ va_list vargs;
+ PyObject *meth;
+ PyObject *args;
+ PyObject *res;
+
+ meth = PyObject_GetAttrString(obj, methodname);
+ if (meth == NULL)
+ return NULL;
+
+ va_start(vargs, format);
+
+ args = Py_VaBuildValue(format, vargs);
+ va_end(vargs);
+
+ if (args == NULL) {
+ Py_DECREF(meth);
+ return NULL;
+ }
+
+ res = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ Py_DECREF(args);
+
+ return res;
+}
+
+int
+PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
+{
+ PyObject *dict;
+ if (!PyModule_Check(m)) {
+ PyErr_SetString(PyExc_TypeError,
+ "PyModule_AddObject() needs module as first arg");
+ return -1;
+ }
+ if (!o) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "PyModule_AddObject() needs non-NULL value");
+ return -1;
+ }
+
+ dict = PyModule_GetDict(m);
+ if (dict == NULL) {
+ /* Internal error -- modules must have a dict! */
+ PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__",
+ PyModule_GetName(m));
+ return -1;
+ }
+ if (PyDict_SetItemString(dict, name, o))
+ return -1;
+ Py_DECREF(o);
+ return 0;
+}
+
+int
+PyModule_AddIntConstant(PyObject *m, const char *name, long value)
+{
+ PyObject *o = PyInt_FromLong(value);
+ if (!o)
+ return -1;
+ if (PyModule_AddObject(m, name, o) == 0)
+ return 0;
+ Py_DECREF(o);
+ return -1;
+}
+
+int
+PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
+{
+ PyObject *o = PyString_FromString(value);
+ if (!o)
+ return -1;
+ if (PyModule_AddObject(m, name, o) == 0)
+ return 0;
+ Py_DECREF(o);
+ return -1;
+}
diff --git a/contrib/tools/python/src/Python/mysnprintf.c b/contrib/tools/python/src/Python/mysnprintf.c
new file mode 100644
index 0000000000..39e3ff1a4d
--- /dev/null
+++ b/contrib/tools/python/src/Python/mysnprintf.c
@@ -0,0 +1,105 @@
+#include "Python.h"
+#include <ctype.h>
+
+/* snprintf() wrappers. If the platform has vsnprintf, we use it, else we
+ emulate it in a half-hearted way. Even if the platform has it, we wrap
+ it because platforms differ in what vsnprintf does in case the buffer
+ is too small: C99 behavior is to return the number of characters that
+ would have been written had the buffer not been too small, and to set
+ the last byte of the buffer to \0. At least MS _vsnprintf returns a
+ negative value instead, and fills the entire buffer with non-\0 data.
+
+ The wrappers ensure that str[size-1] is always \0 upon return.
+
+ PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
+ (including the trailing '\0') into str.
+
+ If the platform doesn't have vsnprintf, and the buffer size needed to
+ avoid truncation exceeds size by more than 512, Python aborts with a
+ Py_FatalError.
+
+ Return value (rv):
+
+ When 0 <= rv < size, the output conversion was unexceptional, and
+ rv characters were written to str (excluding a trailing \0 byte at
+ str[rv]).
+
+ When rv >= size, output conversion was truncated, and a buffer of
+ size rv+1 would have been needed to avoid truncation. str[size-1]
+ is \0 in this case.
+
+ When rv < 0, "something bad happened". str[size-1] is \0 in this
+ case too, but the rest of str is unreliable. It could be that
+ an error in format codes was detected by libc, or on platforms
+ with a non-C99 vsnprintf simply that the buffer wasn't big enough
+ to avoid truncation, or on platforms without any vsnprintf that
+ PyMem_Malloc couldn't obtain space for a temp buffer.
+
+ CAUTION: Unlike C99, str != NULL and size > 0 are required.
+*/
+
+int
+PyOS_snprintf(char *str, size_t size, const char *format, ...)
+{
+ int rc;
+ va_list va;
+
+ va_start(va, format);
+ rc = PyOS_vsnprintf(str, size, format, va);
+ va_end(va);
+ return rc;
+}
+
+int
+PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
+{
+ int len; /* # bytes written, excluding \0 */
+#ifdef HAVE_SNPRINTF
+#define _PyOS_vsnprintf_EXTRA_SPACE 1
+#else
+#define _PyOS_vsnprintf_EXTRA_SPACE 512
+ char *buffer;
+#endif
+ assert(str != NULL);
+ assert(size > 0);
+ assert(format != NULL);
+ /* We take a size_t as input but return an int. Sanity check
+ * our input so that it won't cause an overflow in the
+ * vsnprintf return value or the buffer malloc size. */
+ if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
+ len = -666;
+ goto Done;
+ }
+
+#ifdef HAVE_SNPRINTF
+ len = vsnprintf(str, size, format, va);
+#else
+ /* Emulate it. */
+ buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
+ if (buffer == NULL) {
+ len = -666;
+ goto Done;
+ }
+
+ len = vsprintf(buffer, format, va);
+ if (len < 0)
+ /* ignore the error */;
+
+ else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE)
+ Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf");
+
+ else {
+ const size_t to_copy = (size_t)len < size ?
+ (size_t)len : size - 1;
+ assert(to_copy < size);
+ memcpy(str, buffer, to_copy);
+ str[to_copy] = '\0';
+ }
+ PyMem_FREE(buffer);
+#endif
+Done:
+ if (size > 0)
+ str[size-1] = '\0';
+ return len;
+#undef _PyOS_vsnprintf_EXTRA_SPACE
+}
diff --git a/contrib/tools/python/src/Python/mystrtoul.c b/contrib/tools/python/src/Python/mystrtoul.c
new file mode 100644
index 0000000000..c35be819f6
--- /dev/null
+++ b/contrib/tools/python/src/Python/mystrtoul.c
@@ -0,0 +1,285 @@
+
+#include "Python.h"
+
+#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
+#define _SGI_MP_SOURCE
+#endif
+
+/* strtol and strtoul, renamed to avoid conflicts */
+
+
+#include <ctype.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+/* Static overflow check values for bases 2 through 36.
+ * smallmax[base] is the largest unsigned long i such that
+ * i * base doesn't overflow unsigned long.
+ */
+static unsigned long smallmax[] = {
+ 0, /* bases 0 and 1 are invalid */
+ 0,
+ ULONG_MAX / 2,
+ ULONG_MAX / 3,
+ ULONG_MAX / 4,
+ ULONG_MAX / 5,
+ ULONG_MAX / 6,
+ ULONG_MAX / 7,
+ ULONG_MAX / 8,
+ ULONG_MAX / 9,
+ ULONG_MAX / 10,
+ ULONG_MAX / 11,
+ ULONG_MAX / 12,
+ ULONG_MAX / 13,
+ ULONG_MAX / 14,
+ ULONG_MAX / 15,
+ ULONG_MAX / 16,
+ ULONG_MAX / 17,
+ ULONG_MAX / 18,
+ ULONG_MAX / 19,
+ ULONG_MAX / 20,
+ ULONG_MAX / 21,
+ ULONG_MAX / 22,
+ ULONG_MAX / 23,
+ ULONG_MAX / 24,
+ ULONG_MAX / 25,
+ ULONG_MAX / 26,
+ ULONG_MAX / 27,
+ ULONG_MAX / 28,
+ ULONG_MAX / 29,
+ ULONG_MAX / 30,
+ ULONG_MAX / 31,
+ ULONG_MAX / 32,
+ ULONG_MAX / 33,
+ ULONG_MAX / 34,
+ ULONG_MAX / 35,
+ ULONG_MAX / 36,
+};
+
+/* maximum digits that can't ever overflow for bases 2 through 36,
+ * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
+ * Note that this is pessimistic if sizeof(long) > 4.
+ */
+#if SIZEOF_LONG == 4
+static int digitlimit[] = {
+ 0, 0, 32, 20, 16, 13, 12, 11, 10, 10, /* 0 - 9 */
+ 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, /* 10 - 19 */
+ 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, /* 20 - 29 */
+ 6, 6, 6, 6, 6, 6, 6}; /* 30 - 36 */
+#elif SIZEOF_LONG == 8
+/* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
+static int digitlimit[] = {
+ 0, 0, 64, 40, 32, 27, 24, 22, 21, 20, /* 0 - 9 */
+ 19, 18, 17, 17, 16, 16, 16, 15, 15, 15, /* 10 - 19 */
+ 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, /* 20 - 29 */
+ 13, 12, 12, 12, 12, 12, 12}; /* 30 - 36 */
+#else
+#error "Need table for SIZEOF_LONG"
+#endif
+
+/*
+** strtoul
+** This is a general purpose routine for converting
+** an ascii string to an integer in an arbitrary base.
+** Leading white space is ignored. If 'base' is zero
+** it looks for a leading 0, 0b, 0B, 0o, 0O, 0x or 0X
+** to tell which base. If these are absent it defaults
+** to 10. Base must be 0 or between 2 and 36 (inclusive).
+** If 'ptr' is non-NULL it will contain a pointer to
+** the end of the scan.
+** Errors due to bad pointers will probably result in
+** exceptions - we don't check for them.
+*/
+unsigned long
+PyOS_strtoul(register char *str, char **ptr, int base)
+{
+ register unsigned long result = 0; /* return value of the function */
+ register int c; /* current input character */
+ register int ovlimit; /* required digits to overflow */
+
+ /* skip leading white space */
+ while (*str && isspace(Py_CHARMASK(*str)))
+ ++str;
+
+ /* check for leading 0 or 0x for auto-base or base 16 */
+ switch (base) {
+ case 0: /* look for leading 0, 0b, 0o or 0x */
+ if (*str == '0') {
+ ++str;
+ if (*str == 'x' || *str == 'X') {
+ /* there must be at least one digit after 0x */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ base = 16;
+ } else if (*str == 'o' || *str == 'O') {
+ /* there must be at least one digit after 0o */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ base = 8;
+ } else if (*str == 'b' || *str == 'B') {
+ /* there must be at least one digit after 0b */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ base = 2;
+ } else {
+ base = 8;
+ }
+ }
+ else
+ base = 10;
+ break;
+
+ case 2: /* skip leading 0b or 0B */
+ if (*str == '0') {
+ ++str;
+ if (*str == 'b' || *str == 'B') {
+ /* there must be at least one digit after 0b */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ }
+ }
+ break;
+
+ case 8: /* skip leading 0o or 0O */
+ if (*str == '0') {
+ ++str;
+ if (*str == 'o' || *str == 'O') {
+ /* there must be at least one digit after 0o */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ }
+ }
+ break;
+
+ case 16: /* skip leading 0x or 0X */
+ if (*str == '0') {
+ ++str;
+ if (*str == 'x' || *str == 'X') {
+ /* there must be at least one digit after 0x */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+ ++str;
+ }
+ }
+ break;
+ }
+
+ /* catch silly bases */
+ if (base < 2 || base > 36) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
+
+ /* skip leading zeroes */
+ while (*str == '0')
+ ++str;
+
+ /* base is guaranteed to be in [2, 36] at this point */
+ ovlimit = digitlimit[base];
+
+ /* do the conversion until non-digit character encountered */
+ while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
+ if (ovlimit > 0) /* no overflow check required */
+ result = result * base + c;
+ else { /* requires overflow check */
+ register unsigned long temp_result;
+
+ if (ovlimit < 0) /* guaranteed overflow */
+ goto overflowed;
+
+ /* there could be an overflow */
+ /* check overflow just from shifting */
+ if (result > smallmax[base])
+ goto overflowed;
+
+ result *= base;
+
+ /* check overflow from the digit's value */
+ temp_result = result + c;
+ if (temp_result < result)
+ goto overflowed;
+
+ result = temp_result;
+ }
+
+ ++str;
+ --ovlimit;
+ }
+
+ /* set pointer to point to the last character scanned */
+ if (ptr)
+ *ptr = str;
+
+ return result;
+
+overflowed:
+ if (ptr) {
+ /* spool through remaining digit characters */
+ while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
+ ++str;
+ *ptr = str;
+ }
+ errno = ERANGE;
+ return (unsigned long)-1;
+}
+
+/* Checking for overflow in PyOS_strtol is a PITA; see comments
+ * about PY_ABS_LONG_MIN in longobject.c.
+ */
+#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
+
+long
+PyOS_strtol(char *str, char **ptr, int base)
+{
+ long result;
+ unsigned long uresult;
+ char sign;
+
+ while (*str && isspace(Py_CHARMASK(*str)))
+ str++;
+
+ sign = *str;
+ if (sign == '+' || sign == '-')
+ str++;
+
+ uresult = PyOS_strtoul(str, ptr, base);
+
+ if (uresult <= (unsigned long)LONG_MAX) {
+ result = (long)uresult;
+ if (sign == '-')
+ result = -result;
+ }
+ else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
+ result = LONG_MIN;
+ }
+ else {
+ errno = ERANGE;
+ result = LONG_MAX;
+ }
+ return result;
+}
diff --git a/contrib/tools/python/src/Python/opcode_targets.h b/contrib/tools/python/src/Python/opcode_targets.h
new file mode 100644
index 0000000000..95eb127a15
--- /dev/null
+++ b/contrib/tools/python/src/Python/opcode_targets.h
@@ -0,0 +1,258 @@
+static void *opcode_targets[256] = {
+ &&_unknown_opcode,
+ &&TARGET_POP_TOP,
+ &&TARGET_ROT_TWO,
+ &&TARGET_ROT_THREE,
+ &&TARGET_DUP_TOP,
+ &&TARGET_ROT_FOUR,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_NOP,
+ &&TARGET_UNARY_POSITIVE,
+ &&TARGET_UNARY_NEGATIVE,
+ &&TARGET_UNARY_NOT,
+ &&TARGET_UNARY_CONVERT,
+ &&_unknown_opcode,
+ &&TARGET_UNARY_INVERT,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_BINARY_POWER,
+ &&TARGET_BINARY_MULTIPLY,
+ &&TARGET_BINARY_DIVIDE,
+ &&TARGET_BINARY_MODULO,
+ &&TARGET_BINARY_ADD,
+ &&TARGET_BINARY_SUBTRACT,
+ &&TARGET_BINARY_SUBSCR,
+ &&TARGET_BINARY_FLOOR_DIVIDE,
+ &&TARGET_BINARY_TRUE_DIVIDE,
+ &&TARGET_INPLACE_FLOOR_DIVIDE,
+ &&TARGET_INPLACE_TRUE_DIVIDE,
+ &&TARGET_SLICE ,
+ &&TARGET_SLICE_1,
+ &&TARGET_SLICE_2,
+ &&TARGET_SLICE_3,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_STORE_SLICE ,
+ &&TARGET_STORE_SLICE_1,
+ &&TARGET_STORE_SLICE_2,
+ &&TARGET_STORE_SLICE_3,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_DELETE_SLICE ,
+ &&TARGET_DELETE_SLICE_1,
+ &&TARGET_DELETE_SLICE_2,
+ &&TARGET_DELETE_SLICE_3,
+ &&TARGET_STORE_MAP,
+ &&TARGET_INPLACE_ADD,
+ &&TARGET_INPLACE_SUBTRACT,
+ &&TARGET_INPLACE_MULTIPLY,
+ &&TARGET_INPLACE_DIVIDE,
+ &&TARGET_INPLACE_MODULO,
+ &&TARGET_STORE_SUBSCR,
+ &&TARGET_DELETE_SUBSCR,
+ &&TARGET_BINARY_LSHIFT,
+ &&TARGET_BINARY_RSHIFT,
+ &&TARGET_BINARY_AND,
+ &&TARGET_BINARY_XOR,
+ &&TARGET_BINARY_OR,
+ &&TARGET_INPLACE_POWER,
+ &&TARGET_GET_ITER,
+ &&_unknown_opcode,
+ &&TARGET_PRINT_EXPR,
+ &&TARGET_PRINT_ITEM,
+ &&TARGET_PRINT_NEWLINE,
+ &&TARGET_PRINT_ITEM_TO,
+ &&TARGET_PRINT_NEWLINE_TO,
+ &&TARGET_INPLACE_LSHIFT,
+ &&TARGET_INPLACE_RSHIFT,
+ &&TARGET_INPLACE_AND,
+ &&TARGET_INPLACE_XOR,
+ &&TARGET_INPLACE_OR,
+ &&TARGET_BREAK_LOOP,
+ &&TARGET_WITH_CLEANUP,
+ &&TARGET_LOAD_LOCALS,
+ &&TARGET_RETURN_VALUE,
+ &&TARGET_IMPORT_STAR,
+ &&TARGET_EXEC_STMT,
+ &&TARGET_YIELD_VALUE,
+ &&TARGET_POP_BLOCK,
+ &&TARGET_END_FINALLY,
+ &&TARGET_BUILD_CLASS,
+ &&TARGET_STORE_NAME,
+ &&TARGET_DELETE_NAME,
+ &&TARGET_UNPACK_SEQUENCE,
+ &&TARGET_FOR_ITER,
+ &&TARGET_LIST_APPEND,
+ &&TARGET_STORE_ATTR,
+ &&TARGET_DELETE_ATTR,
+ &&TARGET_STORE_GLOBAL,
+ &&TARGET_DELETE_GLOBAL,
+ &&TARGET_DUP_TOPX,
+ &&TARGET_LOAD_CONST,
+ &&TARGET_LOAD_NAME,
+ &&TARGET_BUILD_TUPLE,
+ &&TARGET_BUILD_LIST,
+ &&TARGET_BUILD_SET,
+ &&TARGET_BUILD_MAP,
+ &&TARGET_LOAD_ATTR,
+ &&TARGET_COMPARE_OP,
+ &&TARGET_IMPORT_NAME,
+ &&TARGET_IMPORT_FROM,
+ &&TARGET_JUMP_FORWARD,
+ &&TARGET_JUMP_IF_FALSE_OR_POP,
+ &&TARGET_JUMP_IF_TRUE_OR_POP,
+ &&TARGET_JUMP_ABSOLUTE,
+ &&TARGET_POP_JUMP_IF_FALSE,
+ &&TARGET_POP_JUMP_IF_TRUE,
+ &&TARGET_LOAD_GLOBAL,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_CONTINUE_LOOP,
+ &&TARGET_SETUP_LOOP,
+ &&TARGET_SETUP_EXCEPT,
+ &&TARGET_SETUP_FINALLY,
+ &&_unknown_opcode,
+ &&TARGET_LOAD_FAST,
+ &&TARGET_STORE_FAST,
+ &&TARGET_DELETE_FAST,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_RAISE_VARARGS,
+ &&TARGET_CALL_FUNCTION,
+ &&TARGET_MAKE_FUNCTION,
+ &&TARGET_BUILD_SLICE,
+ &&TARGET_MAKE_CLOSURE,
+ &&TARGET_LOAD_CLOSURE,
+ &&TARGET_LOAD_DEREF,
+ &&TARGET_STORE_DEREF,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&TARGET_CALL_FUNCTION_VAR,
+ &&TARGET_CALL_FUNCTION_KW,
+ &&TARGET_CALL_FUNCTION_VAR_KW,
+ &&TARGET_SETUP_WITH,
+ &&_unknown_opcode,
+ &&TARGET_EXTENDED_ARG,
+ &&TARGET_SET_ADD,
+ &&TARGET_MAP_ADD,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode
+};
diff --git a/contrib/tools/python/src/Python/peephole.c b/contrib/tools/python/src/Python/peephole.c
new file mode 100644
index 0000000000..5b96c0f8e6
--- /dev/null
+++ b/contrib/tools/python/src/Python/peephole.c
@@ -0,0 +1,674 @@
+/* Peephole optimizations for bytecode compiler. */
+
+#include "Python.h"
+
+#include "Python-ast.h"
+#include "node.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+#include "opcode.h"
+
+#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
+#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
+#define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
+ || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
+#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP \
+ || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
+ || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
+#define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP)
+#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
+#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
+#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
+#define ISBASICBLOCK(blocks, start, bytes) \
+ (blocks[start]==blocks[start+bytes-1])
+
+/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n
+ with LOAD_CONST (c1, c2, ... cn).
+ The consts table must still be in list form so that the
+ new constant (c1, c2, ... cn) can be appended.
+ Called with codestr pointing to the first LOAD_CONST.
+ Bails out with no change if one or more of the LOAD_CONSTs is missing.
+ Also works for BUILD_LIST when followed by an "in" or "not in" test.
+*/
+static int
+tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts)
+{
+ PyObject *newconst, *constant;
+ Py_ssize_t i, arg, len_consts;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST);
+ assert(GETARG(codestr, (n*3)) == n);
+ for (i=0 ; i<n ; i++)
+ assert(codestr[i*3] == LOAD_CONST);
+
+ /* Buildup new tuple of constants */
+ newconst = PyTuple_New(n);
+ if (newconst == NULL)
+ return 0;
+ len_consts = PyList_GET_SIZE(consts);
+ for (i=0 ; i<n ; i++) {
+ arg = GETARG(codestr, (i*3));
+ assert(arg < len_consts);
+ constant = PyList_GET_ITEM(consts, arg);
+ Py_INCREF(constant);
+ PyTuple_SET_ITEM(newconst, i, constant);
+ }
+
+ /* Append folded constant onto consts */
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOPs over old LOAD_CONSTS and
+ add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
+ memset(codestr, NOP, n*3);
+ codestr[n*3] = LOAD_CONST;
+ SETARG(codestr, (n*3), len_consts);
+ return 1;
+}
+
+/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
+ with LOAD_CONST binop(c1,c2)
+ The consts table must still be in list form so that the
+ new constant can be appended.
+ Called with codestr pointing to the first LOAD_CONST.
+ Abandons the transformation if the folding fails (i.e. 1+'a').
+ If the new constant is a sequence, only folds when the size
+ is below a threshold value. That keeps pyc files from
+ becoming large in the presence of code like: (None,)*1000.
+*/
+static int
+fold_binops_on_constants(unsigned char *codestr, PyObject *consts)
+{
+ PyObject *newconst, *v, *w;
+ Py_ssize_t len_consts, size;
+ int opcode;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[0] == LOAD_CONST);
+ assert(codestr[3] == LOAD_CONST);
+
+ /* Create new constant */
+ v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
+ w = PyList_GET_ITEM(consts, GETARG(codestr, 3));
+ opcode = codestr[6];
+ switch (opcode) {
+ case BINARY_POWER:
+ newconst = PyNumber_Power(v, w, Py_None);
+ break;
+ case BINARY_MULTIPLY:
+ newconst = PyNumber_Multiply(v, w);
+ break;
+ case BINARY_DIVIDE:
+ /* Cannot fold this operation statically since
+ the result can depend on the run-time presence
+ of the -Qnew flag */
+ return 0;
+ case BINARY_TRUE_DIVIDE:
+ newconst = PyNumber_TrueDivide(v, w);
+ break;
+ case BINARY_FLOOR_DIVIDE:
+ newconst = PyNumber_FloorDivide(v, w);
+ break;
+ case BINARY_MODULO:
+ newconst = PyNumber_Remainder(v, w);
+ break;
+ case BINARY_ADD:
+ newconst = PyNumber_Add(v, w);
+ break;
+ case BINARY_SUBTRACT:
+ newconst = PyNumber_Subtract(v, w);
+ break;
+ case BINARY_SUBSCR:
+ /* #5057: if v is unicode, there might be differences between
+ wide and narrow builds in cases like '\U00012345'[0] or
+ '\U00012345abcdef'[3], so it's better to skip the optimization
+ in order to produce compatible pycs.
+ */
+ if (PyUnicode_Check(v))
+ return 0;
+ newconst = PyObject_GetItem(v, w);
+ break;
+ case BINARY_LSHIFT:
+ newconst = PyNumber_Lshift(v, w);
+ break;
+ case BINARY_RSHIFT:
+ newconst = PyNumber_Rshift(v, w);
+ break;
+ case BINARY_AND:
+ newconst = PyNumber_And(v, w);
+ break;
+ case BINARY_XOR:
+ newconst = PyNumber_Xor(v, w);
+ break;
+ case BINARY_OR:
+ newconst = PyNumber_Or(v, w);
+ break;
+ default:
+ /* Called with an unknown opcode */
+ PyErr_Format(PyExc_SystemError,
+ "unexpected binary operation %d on a constant",
+ opcode);
+ return 0;
+ }
+ if (newconst == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ size = PyObject_Size(newconst);
+ if (size == -1)
+ PyErr_Clear();
+ else if (size > 20) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+
+ /* Append folded constant into consts table */
+ len_consts = PyList_GET_SIZE(consts);
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOP NOP NOP NOP LOAD_CONST newconst */
+ memset(codestr, NOP, 4);
+ codestr[4] = LOAD_CONST;
+ SETARG(codestr, 4, len_consts);
+ return 1;
+}
+
+static int
+fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts)
+{
+ PyObject *newconst=NULL, *v;
+ Py_ssize_t len_consts;
+ int opcode;
+
+ /* Pre-conditions */
+ assert(PyList_CheckExact(consts));
+ assert(codestr[0] == LOAD_CONST);
+
+ /* Create new constant */
+ v = PyList_GET_ITEM(consts, GETARG(codestr, 0));
+ opcode = codestr[3];
+ switch (opcode) {
+ case UNARY_NEGATIVE:
+ /* Preserve the sign of -0.0 */
+ if (PyObject_IsTrue(v) == 1)
+ newconst = PyNumber_Negative(v);
+ break;
+ case UNARY_CONVERT:
+ newconst = PyObject_Repr(v);
+ break;
+ case UNARY_INVERT:
+ newconst = PyNumber_Invert(v);
+ break;
+ default:
+ /* Called with an unknown opcode */
+ PyErr_Format(PyExc_SystemError,
+ "unexpected unary operation %d on a constant",
+ opcode);
+ return 0;
+ }
+ if (newconst == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ /* Append folded constant into consts table */
+ len_consts = PyList_GET_SIZE(consts);
+ if (PyList_Append(consts, newconst)) {
+ Py_DECREF(newconst);
+ return 0;
+ }
+ Py_DECREF(newconst);
+
+ /* Write NOP LOAD_CONST newconst */
+ codestr[0] = NOP;
+ codestr[1] = LOAD_CONST;
+ SETARG(codestr, 1, len_consts);
+ return 1;
+}
+
+static unsigned int *
+markblocks(unsigned char *code, Py_ssize_t len)
+{
+ unsigned int *blocks = PyMem_New(unsigned int, len);
+ int i,j, opcode, blockcnt = 0;
+
+ if (blocks == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset(blocks, 0, len*sizeof(int));
+
+ /* Mark labels in the first pass */
+ for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
+ opcode = code[i];
+ switch (opcode) {
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case JUMP_IF_FALSE_OR_POP:
+ case JUMP_IF_TRUE_OR_POP:
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE:
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ case SETUP_WITH:
+ j = GETJUMPTGT(code, i);
+ blocks[j] = 1;
+ break;
+ }
+ }
+ /* Build block numbers in the second pass */
+ for (i=0 ; i<len ; i++) {
+ blockcnt += blocks[i]; /* increment blockcnt over labels */
+ blocks[i] = blockcnt;
+ }
+ return blocks;
+}
+
+/* Perform basic peephole optimizations to components of a code object.
+ The consts object should still be in list form to allow new constants
+ to be appended.
+
+ To keep the optimizer simple, it bails out (does nothing) for code
+ containing extended arguments or that has a length over 32,700. That
+ allows us to avoid overflow and sign issues. Likewise, it bails when
+ the lineno table has complex encoding for gaps >= 255.
+
+ Optimizations are restricted to simple transformations occurring within a
+ single basic block. All transformations keep the code size the same or
+ smaller. For those that reduce size, the gaps are initially filled with
+ NOPs. Later those NOPs are removed and the jump addresses retargeted in
+ a single pass. Code offset is adjusted accordingly. */
+
+PyObject *
+PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
+ PyObject *lnotab_obj)
+{
+ Py_ssize_t i, j, codelen;
+ int nops, h, adj;
+ int tgt, tgttgt, opcode;
+ unsigned char *codestr = NULL;
+ unsigned char *lnotab;
+ int *addrmap = NULL;
+ int cum_orig_offset, last_offset;
+ Py_ssize_t tabsiz;
+ int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONSTs */
+ unsigned int *blocks = NULL;
+ char *name;
+
+ /* Bail out if an exception is set */
+ if (PyErr_Occurred())
+ goto exitError;
+
+ /* Bypass optimization when the lnotab table is too complex */
+ assert(PyString_Check(lnotab_obj));
+ lnotab = (unsigned char*)PyString_AS_STRING(lnotab_obj);
+ tabsiz = PyString_GET_SIZE(lnotab_obj);
+ assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
+ if (memchr(lnotab, 255, tabsiz) != NULL) {
+ /* 255 value are used for multibyte bytecode instructions */
+ goto exitUnchanged;
+ }
+ /* Note: -128 and 127 special values for line number delta are ok,
+ the peephole optimizer doesn't modify line numbers. */
+
+ /* Avoid situations where jump retargeting could overflow */
+ assert(PyString_Check(code));
+ codelen = PyString_GET_SIZE(code);
+ if (codelen > 32700)
+ goto exitUnchanged;
+
+ /* Make a modifiable copy of the code string */
+ codestr = (unsigned char *)PyMem_Malloc(codelen);
+ if (codestr == NULL)
+ goto exitError;
+ codestr = (unsigned char *)memcpy(codestr,
+ PyString_AS_STRING(code), codelen);
+
+ /* Verify that RETURN_VALUE terminates the codestring. This allows
+ the various transformation patterns to look ahead several
+ instructions without additional checks to make sure they are not
+ looking beyond the end of the code string.
+ */
+ if (codestr[codelen-1] != RETURN_VALUE)
+ goto exitUnchanged;
+
+ /* Mapping to new jump targets after NOPs are removed */
+ addrmap = PyMem_New(int, codelen);
+ if (addrmap == NULL) {
+ PyErr_NoMemory();
+ goto exitError;
+ }
+
+ blocks = markblocks(codestr, codelen);
+ if (blocks == NULL)
+ goto exitError;
+ assert(PyList_Check(consts));
+
+ for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
+ reoptimize_current:
+ opcode = codestr[i];
+
+ lastlc = cumlc;
+ cumlc = 0;
+
+ switch (opcode) {
+ /* Replace UNARY_NOT POP_JUMP_IF_FALSE
+ with POP_JUMP_IF_TRUE */
+ case UNARY_NOT:
+ if (codestr[i+1] != POP_JUMP_IF_FALSE
+ || !ISBASICBLOCK(blocks,i,4))
+ continue;
+ j = GETARG(codestr, i+1);
+ codestr[i] = POP_JUMP_IF_TRUE;
+ SETARG(codestr, i, j);
+ codestr[i+3] = NOP;
+ goto reoptimize_current;
+
+ /* not a is b --> a is not b
+ not a in b --> a not in b
+ not a is not b --> a is b
+ not a not in b --> a in b
+ */
+ case COMPARE_OP:
+ j = GETARG(codestr, i);
+ if (j < 6 || j > 9 ||
+ codestr[i+3] != UNARY_NOT ||
+ !ISBASICBLOCK(blocks,i,4))
+ continue;
+ SETARG(codestr, i, (j^1));
+ codestr[i+3] = NOP;
+ break;
+
+ /* Replace LOAD_GLOBAL/LOAD_NAME None
+ with LOAD_CONST None */
+ case LOAD_NAME:
+ case LOAD_GLOBAL:
+ j = GETARG(codestr, i);
+ name = PyString_AsString(PyTuple_GET_ITEM(names, j));
+ if (name == NULL || strcmp(name, "None") != 0)
+ continue;
+ for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) {
+ if (PyList_GET_ITEM(consts, j) == Py_None)
+ break;
+ }
+ if (j == PyList_GET_SIZE(consts)) {
+ if (PyList_Append(consts, Py_None) == -1)
+ goto exitError;
+ }
+ assert(PyList_GET_ITEM(consts, j) == Py_None);
+ codestr[i] = LOAD_CONST;
+ SETARG(codestr, i, j);
+ cumlc = lastlc + 1;
+ break;
+
+ /* Skip over LOAD_CONST trueconst
+ POP_JUMP_IF_FALSE xx. This improves
+ "while 1" performance. */
+ case LOAD_CONST:
+ cumlc = lastlc + 1;
+ j = GETARG(codestr, i);
+ if (codestr[i+3] != POP_JUMP_IF_FALSE ||
+ !ISBASICBLOCK(blocks,i,6) ||
+ !PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
+ continue;
+ memset(codestr+i, NOP, 6);
+ cumlc = 0;
+ break;
+
+ /* Try to fold tuples of constants (includes a case for lists
+ which are only used for "in" and "not in" tests).
+ Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
+ Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
+ Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
+ case BUILD_TUPLE:
+ case BUILD_LIST:
+ j = GETARG(codestr, i);
+ h = i - 3 * j;
+ if (h >= 0 &&
+ j <= lastlc &&
+ ((opcode == BUILD_TUPLE &&
+ ISBASICBLOCK(blocks, h, 3*(j+1))) ||
+ (opcode == BUILD_LIST &&
+ codestr[i+3]==COMPARE_OP &&
+ ISBASICBLOCK(blocks, h, 3*(j+2)) &&
+ (GETARG(codestr,i+3)==6 ||
+ GETARG(codestr,i+3)==7))) &&
+ tuple_of_constants(&codestr[h], j, consts)) {
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ break;
+ }
+ if (codestr[i+3] != UNPACK_SEQUENCE ||
+ !ISBASICBLOCK(blocks,i,6) ||
+ j != GETARG(codestr, i+3))
+ continue;
+ if (j == 1) {
+ memset(codestr+i, NOP, 6);
+ } else if (j == 2) {
+ codestr[i] = ROT_TWO;
+ memset(codestr+i+1, NOP, 5);
+ } else if (j == 3) {
+ codestr[i] = ROT_THREE;
+ codestr[i+1] = ROT_TWO;
+ memset(codestr+i+2, NOP, 4);
+ }
+ break;
+
+ /* Fold binary ops on constants.
+ LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
+ case BINARY_POWER:
+ case BINARY_MULTIPLY:
+ case BINARY_TRUE_DIVIDE:
+ case BINARY_FLOOR_DIVIDE:
+ case BINARY_MODULO:
+ case BINARY_ADD:
+ case BINARY_SUBTRACT:
+ case BINARY_SUBSCR:
+ case BINARY_LSHIFT:
+ case BINARY_RSHIFT:
+ case BINARY_AND:
+ case BINARY_XOR:
+ case BINARY_OR:
+ if (lastlc >= 2 &&
+ ISBASICBLOCK(blocks, i-6, 7) &&
+ fold_binops_on_constants(&codestr[i-6], consts)) {
+ i -= 2;
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ }
+ break;
+
+ /* Fold unary ops on constants.
+ LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
+ case UNARY_NEGATIVE:
+ case UNARY_CONVERT:
+ case UNARY_INVERT:
+ if (lastlc >= 1 &&
+ ISBASICBLOCK(blocks, i-3, 4) &&
+ fold_unaryops_on_constants(&codestr[i-3], consts)) {
+ i -= 2;
+ assert(codestr[i] == LOAD_CONST);
+ cumlc = 1;
+ }
+ break;
+
+ /* Simplify conditional jump to conditional jump where the
+ result of the first test implies the success of a similar
+ test or the failure of the opposite test.
+ Arises in code like:
+ "if a and b:"
+ "if a or b:"
+ "a and b or c"
+ "(a and b) and c"
+ x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
+ --> x:JUMP_IF_FALSE_OR_POP z
+ x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
+ --> x:POP_JUMP_IF_FALSE y+3
+ where y+3 is the instruction following the second test.
+ */
+ case JUMP_IF_FALSE_OR_POP:
+ case JUMP_IF_TRUE_OR_POP:
+ tgt = GETJUMPTGT(codestr, i);
+ j = codestr[tgt];
+ if (CONDITIONAL_JUMP(j)) {
+ /* NOTE: all possible jumps here are absolute! */
+ if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
+ /* The second jump will be
+ taken iff the first is. */
+ tgttgt = GETJUMPTGT(codestr, tgt);
+ /* The current opcode inherits
+ its target's stack behaviour */
+ codestr[i] = j;
+ SETARG(codestr, i, tgttgt);
+ goto reoptimize_current;
+ } else {
+ /* The second jump is not taken if the first is (so
+ jump past it), and all conditional jumps pop their
+ argument when they're not taken (so change the
+ first jump to pop its argument when it's taken). */
+ if (JUMPS_ON_TRUE(opcode))
+ codestr[i] = POP_JUMP_IF_TRUE;
+ else
+ codestr[i] = POP_JUMP_IF_FALSE;
+ SETARG(codestr, i, (tgt + 3));
+ goto reoptimize_current;
+ }
+ }
+ /* Intentional fallthrough */
+
+ /* Replace jumps to unconditional jumps */
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE:
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ case SETUP_WITH:
+ tgt = GETJUMPTGT(codestr, i);
+ /* Replace JUMP_* to a RETURN into just a RETURN */
+ if (UNCONDITIONAL_JUMP(opcode) &&
+ codestr[tgt] == RETURN_VALUE) {
+ codestr[i] = RETURN_VALUE;
+ memset(codestr+i+1, NOP, 2);
+ continue;
+ }
+ if (!UNCONDITIONAL_JUMP(codestr[tgt]))
+ continue;
+ tgttgt = GETJUMPTGT(codestr, tgt);
+ if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
+ opcode = JUMP_ABSOLUTE;
+ if (!ABSOLUTE_JUMP(opcode))
+ tgttgt -= i + 3; /* Calc relative jump addr */
+ if (tgttgt < 0) /* No backward relative jumps */
+ continue;
+ codestr[i] = opcode;
+ SETARG(codestr, i, tgttgt);
+ break;
+
+ case EXTENDED_ARG:
+ goto exitUnchanged;
+
+ /* Replace RETURN LOAD_CONST None RETURN with just RETURN */
+ /* Remove unreachable JUMPs after RETURN */
+ case RETURN_VALUE:
+ if (i+4 >= codelen)
+ continue;
+ if (codestr[i+4] == RETURN_VALUE &&
+ ISBASICBLOCK(blocks,i,5))
+ memset(codestr+i+1, NOP, 4);
+ else if (UNCONDITIONAL_JUMP(codestr[i+1]) &&
+ ISBASICBLOCK(blocks,i,4))
+ memset(codestr+i+1, NOP, 3);
+ break;
+ }
+ }
+
+ /* Fixup lnotab */
+ for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
+ assert(i - nops <= INT_MAX);
+ /* original code offset => new code offset */
+ addrmap[i] = i - nops;
+ if (codestr[i] == NOP)
+ nops++;
+ }
+ cum_orig_offset = 0;
+ last_offset = 0;
+ for (i=0 ; i < tabsiz ; i+=2) {
+ int offset_delta, new_offset;
+ cum_orig_offset += lnotab[i];
+ new_offset = addrmap[cum_orig_offset];
+ offset_delta = new_offset - last_offset;
+ assert(0 <= offset_delta && offset_delta <= 255);
+ lnotab[i] = (unsigned char)offset_delta;
+ last_offset = new_offset;
+ }
+
+ /* Remove NOPs and fixup jump targets */
+ for (i=0, h=0 ; i<codelen ; ) {
+ opcode = codestr[i];
+ switch (opcode) {
+ case NOP:
+ i++;
+ continue;
+
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE:
+ case JUMP_IF_FALSE_OR_POP:
+ case JUMP_IF_TRUE_OR_POP:
+ j = addrmap[GETARG(codestr, i)];
+ SETARG(codestr, i, j);
+ break;
+
+ case FOR_ITER:
+ case JUMP_FORWARD:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ case SETUP_WITH:
+ j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
+ SETARG(codestr, i, j);
+ break;
+ }
+ adj = CODESIZE(opcode);
+ while (adj--)
+ codestr[h++] = codestr[i++];
+ }
+ assert(h + nops == codelen);
+
+ code = PyString_FromStringAndSize((char *)codestr, h);
+ PyMem_Free(addrmap);
+ PyMem_Free(codestr);
+ PyMem_Free(blocks);
+ return code;
+
+ exitError:
+ code = NULL;
+
+ exitUnchanged:
+ PyMem_Free(blocks);
+ PyMem_Free(addrmap);
+ PyMem_Free(codestr);
+ Py_XINCREF(code);
+ return code;
+}
diff --git a/contrib/tools/python/src/Python/pyarena.c b/contrib/tools/python/src/Python/pyarena.c
new file mode 100644
index 0000000000..513b3791d5
--- /dev/null
+++ b/contrib/tools/python/src/Python/pyarena.c
@@ -0,0 +1,213 @@
+#include "Python.h"
+#include "pyarena.h"
+
+/* A simple arena block structure.
+
+ Measurements with standard library modules suggest the average
+ allocation is about 20 bytes and that most compiles use a single
+ block.
+
+ TODO(jhylton): Think about a realloc API, maybe just for the last
+ allocation?
+*/
+
+#define DEFAULT_BLOCK_SIZE 8192
+#define ALIGNMENT 8
+#define ALIGNMENT_MASK (ALIGNMENT - 1)
+#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK)
+
+typedef struct _block {
+ /* Total number of bytes owned by this block available to pass out.
+ * Read-only after initialization. The first such byte starts at
+ * ab_mem.
+ */
+ size_t ab_size;
+
+ /* Total number of bytes already passed out. The next byte available
+ * to pass out starts at ab_mem + ab_offset.
+ */
+ size_t ab_offset;
+
+ /* An arena maintains a singly-linked, NULL-terminated list of
+ * all blocks owned by the arena. These are linked via the
+ * ab_next member.
+ */
+ struct _block *ab_next;
+
+ /* Pointer to the first allocatable byte owned by this block. Read-
+ * only after initialization.
+ */
+ void *ab_mem;
+} block;
+
+/* The arena manages two kinds of memory, blocks of raw memory
+ and a list of PyObject* pointers. PyObjects are decrefed
+ when the arena is freed.
+*/
+
+struct _arena {
+ /* Pointer to the first block allocated for the arena, never NULL.
+ It is used only to find the first block when the arena is
+ being freed.
+ */
+ block *a_head;
+
+ /* Pointer to the block currently used for allocation. It's
+ ab_next field should be NULL. If it is not-null after a
+ call to block_alloc(), it means a new block has been allocated
+ and a_cur should be reset to point it.
+ */
+ block *a_cur;
+
+ /* A Python list object containing references to all the PyObject
+ pointers associated with this area. They will be DECREFed
+ when the arena is freed.
+ */
+ PyObject *a_objects;
+
+#if defined(Py_DEBUG)
+ /* Debug output */
+ size_t total_allocs;
+ size_t total_size;
+ size_t total_blocks;
+ size_t total_block_size;
+ size_t total_big_blocks;
+#endif
+};
+
+static block *
+block_new(size_t size)
+{
+ /* Allocate header and block as one unit.
+ ab_mem points just past header. */
+ block *b = (block *)malloc(sizeof(block) + size);
+ if (!b)
+ return NULL;
+ b->ab_size = size;
+ b->ab_mem = (void *)(b + 1);
+ b->ab_next = NULL;
+ b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) -
+ (Py_uintptr_t)(b->ab_mem);
+ return b;
+}
+
+static void
+block_free(block *b) {
+ while (b) {
+ block *next = b->ab_next;
+ free(b);
+ b = next;
+ }
+}
+
+static void *
+block_alloc(block *b, size_t size)
+{
+ void *p;
+ assert(b);
+ size = ROUNDUP(size);
+ if (b->ab_offset + size > b->ab_size) {
+ /* If we need to allocate more memory than will fit in
+ the default block, allocate a one-off block that is
+ exactly the right size. */
+ /* TODO(jhylton): Think about space waste at end of block */
+ block *newbl = block_new(
+ size < DEFAULT_BLOCK_SIZE ?
+ DEFAULT_BLOCK_SIZE : size);
+ if (!newbl)
+ return NULL;
+ assert(!b->ab_next);
+ b->ab_next = newbl;
+ b = newbl;
+ }
+
+ assert(b->ab_offset + size <= b->ab_size);
+ p = (void *)(((char *)b->ab_mem) + b->ab_offset);
+ b->ab_offset += size;
+ return p;
+}
+
+PyArena *
+PyArena_New()
+{
+ PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
+ if (!arena)
+ return (PyArena*)PyErr_NoMemory();
+
+ arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
+ arena->a_cur = arena->a_head;
+ if (!arena->a_head) {
+ free((void *)arena);
+ return (PyArena*)PyErr_NoMemory();
+ }
+ arena->a_objects = PyList_New(0);
+ if (!arena->a_objects) {
+ block_free(arena->a_head);
+ free((void *)arena);
+ return (PyArena*)PyErr_NoMemory();
+ }
+#if defined(Py_DEBUG)
+ arena->total_allocs = 0;
+ arena->total_size = 0;
+ arena->total_blocks = 1;
+ arena->total_block_size = DEFAULT_BLOCK_SIZE;
+ arena->total_big_blocks = 0;
+#endif
+ return arena;
+}
+
+void
+PyArena_Free(PyArena *arena)
+{
+ assert(arena);
+#if defined(Py_DEBUG)
+ /*
+ fprintf(stderr,
+ "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n",
+ arena->total_allocs, arena->total_size, arena->total_blocks,
+ arena->total_block_size, arena->total_big_blocks,
+ PyList_Size(arena->a_objects));
+ */
+#endif
+ block_free(arena->a_head);
+ /* This property normally holds, except when the code being compiled
+ is sys.getobjects(0), in which case there will be two references.
+ assert(arena->a_objects->ob_refcnt == 1);
+ */
+
+ Py_DECREF(arena->a_objects);
+ free(arena);
+}
+
+void *
+PyArena_Malloc(PyArena *arena, size_t size)
+{
+ void *p = block_alloc(arena->a_cur, size);
+ if (!p)
+ return PyErr_NoMemory();
+#if defined(Py_DEBUG)
+ arena->total_allocs++;
+ arena->total_size += size;
+#endif
+ /* Reset cur if we allocated a new block. */
+ if (arena->a_cur->ab_next) {
+ arena->a_cur = arena->a_cur->ab_next;
+#if defined(Py_DEBUG)
+ arena->total_blocks++;
+ arena->total_block_size += arena->a_cur->ab_size;
+ if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE)
+ ++arena->total_big_blocks;
+#endif
+ }
+ return p;
+}
+
+int
+PyArena_AddPyObject(PyArena *arena, PyObject *obj)
+{
+ int r = PyList_Append(arena->a_objects, obj);
+ if (r >= 0) {
+ Py_DECREF(obj);
+ }
+ return r;
+}
diff --git a/contrib/tools/python/src/Python/pyctype.c b/contrib/tools/python/src/Python/pyctype.c
new file mode 100644
index 0000000000..da117d58fd
--- /dev/null
+++ b/contrib/tools/python/src/Python/pyctype.c
@@ -0,0 +1,214 @@
+#include "Python.h"
+
+/* Our own locale-independent ctype.h-like macros */
+
+const unsigned int _Py_ctype_table[256] = {
+ 0, /* 0x0 '\x00' */
+ 0, /* 0x1 '\x01' */
+ 0, /* 0x2 '\x02' */
+ 0, /* 0x3 '\x03' */
+ 0, /* 0x4 '\x04' */
+ 0, /* 0x5 '\x05' */
+ 0, /* 0x6 '\x06' */
+ 0, /* 0x7 '\x07' */
+ 0, /* 0x8 '\x08' */
+ PY_CTF_SPACE, /* 0x9 '\t' */
+ PY_CTF_SPACE, /* 0xa '\n' */
+ PY_CTF_SPACE, /* 0xb '\v' */
+ PY_CTF_SPACE, /* 0xc '\f' */
+ PY_CTF_SPACE, /* 0xd '\r' */
+ 0, /* 0xe '\x0e' */
+ 0, /* 0xf '\x0f' */
+ 0, /* 0x10 '\x10' */
+ 0, /* 0x11 '\x11' */
+ 0, /* 0x12 '\x12' */
+ 0, /* 0x13 '\x13' */
+ 0, /* 0x14 '\x14' */
+ 0, /* 0x15 '\x15' */
+ 0, /* 0x16 '\x16' */
+ 0, /* 0x17 '\x17' */
+ 0, /* 0x18 '\x18' */
+ 0, /* 0x19 '\x19' */
+ 0, /* 0x1a '\x1a' */
+ 0, /* 0x1b '\x1b' */
+ 0, /* 0x1c '\x1c' */
+ 0, /* 0x1d '\x1d' */
+ 0, /* 0x1e '\x1e' */
+ 0, /* 0x1f '\x1f' */
+ PY_CTF_SPACE, /* 0x20 ' ' */
+ 0, /* 0x21 '!' */
+ 0, /* 0x22 '"' */
+ 0, /* 0x23 '#' */
+ 0, /* 0x24 '$' */
+ 0, /* 0x25 '%' */
+ 0, /* 0x26 '&' */
+ 0, /* 0x27 "'" */
+ 0, /* 0x28 '(' */
+ 0, /* 0x29 ')' */
+ 0, /* 0x2a '*' */
+ 0, /* 0x2b '+' */
+ 0, /* 0x2c ',' */
+ 0, /* 0x2d '-' */
+ 0, /* 0x2e '.' */
+ 0, /* 0x2f '/' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x30 '0' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x31 '1' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x32 '2' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x33 '3' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x34 '4' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x35 '5' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x36 '6' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x37 '7' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x38 '8' */
+ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x39 '9' */
+ 0, /* 0x3a ':' */
+ 0, /* 0x3b ';' */
+ 0, /* 0x3c '<' */
+ 0, /* 0x3d '=' */
+ 0, /* 0x3e '>' */
+ 0, /* 0x3f '?' */
+ 0, /* 0x40 '@' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x41 'A' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x42 'B' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x43 'C' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x44 'D' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x45 'E' */
+ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x46 'F' */
+ PY_CTF_UPPER, /* 0x47 'G' */
+ PY_CTF_UPPER, /* 0x48 'H' */
+ PY_CTF_UPPER, /* 0x49 'I' */
+ PY_CTF_UPPER, /* 0x4a 'J' */
+ PY_CTF_UPPER, /* 0x4b 'K' */
+ PY_CTF_UPPER, /* 0x4c 'L' */
+ PY_CTF_UPPER, /* 0x4d 'M' */
+ PY_CTF_UPPER, /* 0x4e 'N' */
+ PY_CTF_UPPER, /* 0x4f 'O' */
+ PY_CTF_UPPER, /* 0x50 'P' */
+ PY_CTF_UPPER, /* 0x51 'Q' */
+ PY_CTF_UPPER, /* 0x52 'R' */
+ PY_CTF_UPPER, /* 0x53 'S' */
+ PY_CTF_UPPER, /* 0x54 'T' */
+ PY_CTF_UPPER, /* 0x55 'U' */
+ PY_CTF_UPPER, /* 0x56 'V' */
+ PY_CTF_UPPER, /* 0x57 'W' */
+ PY_CTF_UPPER, /* 0x58 'X' */
+ PY_CTF_UPPER, /* 0x59 'Y' */
+ PY_CTF_UPPER, /* 0x5a 'Z' */
+ 0, /* 0x5b '[' */
+ 0, /* 0x5c '\\' */
+ 0, /* 0x5d ']' */
+ 0, /* 0x5e '^' */
+ 0, /* 0x5f '_' */
+ 0, /* 0x60 '`' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x61 'a' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x62 'b' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x63 'c' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x64 'd' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x65 'e' */
+ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x66 'f' */
+ PY_CTF_LOWER, /* 0x67 'g' */
+ PY_CTF_LOWER, /* 0x68 'h' */
+ PY_CTF_LOWER, /* 0x69 'i' */
+ PY_CTF_LOWER, /* 0x6a 'j' */
+ PY_CTF_LOWER, /* 0x6b 'k' */
+ PY_CTF_LOWER, /* 0x6c 'l' */
+ PY_CTF_LOWER, /* 0x6d 'm' */
+ PY_CTF_LOWER, /* 0x6e 'n' */
+ PY_CTF_LOWER, /* 0x6f 'o' */
+ PY_CTF_LOWER, /* 0x70 'p' */
+ PY_CTF_LOWER, /* 0x71 'q' */
+ PY_CTF_LOWER, /* 0x72 'r' */
+ PY_CTF_LOWER, /* 0x73 's' */
+ PY_CTF_LOWER, /* 0x74 't' */
+ PY_CTF_LOWER, /* 0x75 'u' */
+ PY_CTF_LOWER, /* 0x76 'v' */
+ PY_CTF_LOWER, /* 0x77 'w' */
+ PY_CTF_LOWER, /* 0x78 'x' */
+ PY_CTF_LOWER, /* 0x79 'y' */
+ PY_CTF_LOWER, /* 0x7a 'z' */
+ 0, /* 0x7b '{' */
+ 0, /* 0x7c '|' */
+ 0, /* 0x7d '}' */
+ 0, /* 0x7e '~' */
+ 0, /* 0x7f '\x7f' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+
+const unsigned char _Py_ctype_tolower[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
+
+const unsigned char _Py_ctype_toupper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
+
diff --git a/contrib/tools/python/src/Python/pyfpe.c b/contrib/tools/python/src/Python/pyfpe.c
new file mode 100644
index 0000000000..4b7f5bae15
--- /dev/null
+++ b/contrib/tools/python/src/Python/pyfpe.c
@@ -0,0 +1,23 @@
+#include "pyconfig.h"
+#include "pyfpe.h"
+/*
+ * The signal handler for SIGFPE is actually declared in an external
+ * module fpectl, or as preferred by the user. These variable
+ * definitions are required in order to compile Python without
+ * getting missing externals, but to actually handle SIGFPE requires
+ * defining a handler and enabling generation of SIGFPE.
+ */
+
+#ifdef WANT_SIGFPE_HANDLER
+jmp_buf PyFPE_jbuf;
+int PyFPE_counter = 0;
+#endif
+
+/* Have this outside the above #ifdef, since some picky ANSI compilers issue a
+ warning when compiling an empty file. */
+
+double
+PyFPE_dummy(void *dummy)
+{
+ return 1.0;
+}
diff --git a/contrib/tools/python/src/Python/pymath.c b/contrib/tools/python/src/Python/pymath.c
new file mode 100644
index 0000000000..8bde2a8649
--- /dev/null
+++ b/contrib/tools/python/src/Python/pymath.c
@@ -0,0 +1,79 @@
+#include "Python.h"
+
+#ifdef X87_DOUBLE_ROUNDING
+/* On x86 platforms using an x87 FPU, this function is called from the
+ Py_FORCE_DOUBLE macro (defined in pymath.h) to force a floating-point
+ number out of an 80-bit x87 FPU register and into a 64-bit memory location,
+ thus rounding from extended precision to double precision. */
+double _Py_force_double(double x)
+{
+ volatile double y;
+ y = x;
+ return y;
+}
+#endif
+
+#ifdef HAVE_GCC_ASM_FOR_X87
+
+/* inline assembly for getting and setting the 387 FPU control word on
+ gcc/x86 */
+
+unsigned short _Py_get_387controlword(void) {
+ unsigned short cw = 0;
+ __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
+ return cw;
+}
+
+void _Py_set_387controlword(unsigned short cw) {
+ __asm__ __volatile__ ("fldcw %0" : : "m" (cw));
+}
+
+#endif
+
+
+#ifndef HAVE_HYPOT
+double hypot(double x, double y)
+{
+ double yx;
+
+ x = fabs(x);
+ y = fabs(y);
+ if (x < y) {
+ double temp = x;
+ x = y;
+ y = temp;
+ }
+ if (x == 0.)
+ return 0.;
+ else {
+ yx = y/x;
+ return x*sqrt(1.+yx*yx);
+ }
+}
+#endif /* HAVE_HYPOT */
+
+#ifndef HAVE_COPYSIGN
+double
+copysign(double x, double y)
+{
+ /* use atan2 to distinguish -0. from 0. */
+ if (y > 0. || (y == 0. && atan2(y, -1.) > 0.)) {
+ return fabs(x);
+ } else {
+ return -fabs(x);
+ }
+}
+#endif /* HAVE_COPYSIGN */
+
+#ifndef HAVE_ROUND
+double
+round(double x)
+{
+ double absx, y;
+ absx = fabs(x);
+ y = floor(absx);
+ if (absx - y >= 0.5)
+ y += 1.0;
+ return copysign(y, x);
+}
+#endif /* HAVE_ROUND */
diff --git a/contrib/tools/python/src/Python/pystate.c b/contrib/tools/python/src/Python/pystate.c
new file mode 100644
index 0000000000..f33f182023
--- /dev/null
+++ b/contrib/tools/python/src/Python/pystate.c
@@ -0,0 +1,681 @@
+
+/* Thread and interpreter state structures and their interfaces */
+
+#include "Python.h"
+
+/* --------------------------------------------------------------------------
+CAUTION
+
+Always use malloc() and free() directly in this file. A number of these
+functions are advertised as safe to call when the GIL isn't held, and in
+a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's debugging
+obmalloc functions. Those aren't thread-safe (they rely on the GIL to avoid
+the expense of doing their own locking).
+-------------------------------------------------------------------------- */
+
+#ifdef HAVE_DLOPEN
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 1
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WITH_THREAD
+#include "pythread.h"
+static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */
+#define HEAD_INIT() (void)(head_mutex || (head_mutex = PyThread_allocate_lock()))
+#define HEAD_LOCK() PyThread_acquire_lock(head_mutex, WAIT_LOCK)
+#define HEAD_UNLOCK() PyThread_release_lock(head_mutex)
+
+/* The single PyInterpreterState used by this process'
+ GILState implementation
+*/
+static PyInterpreterState *autoInterpreterState = NULL;
+static int autoTLSkey = 0;
+#else
+#define HEAD_INIT() /* Nothing */
+#define HEAD_LOCK() /* Nothing */
+#define HEAD_UNLOCK() /* Nothing */
+#endif
+
+static PyInterpreterState *interp_head = NULL;
+
+PyThreadState *_PyThreadState_Current = NULL;
+PyThreadFrameGetter _PyThreadState_GetFrame = NULL;
+
+#ifdef WITH_THREAD
+static void _PyGILState_NoteThreadState(PyThreadState* tstate);
+#endif
+
+
+PyInterpreterState *
+PyInterpreterState_New(void)
+{
+ PyInterpreterState *interp = (PyInterpreterState *)
+ malloc(sizeof(PyInterpreterState));
+
+ if (interp != NULL) {
+ HEAD_INIT();
+#ifdef WITH_THREAD
+ if (head_mutex == NULL)
+ Py_FatalError("Can't initialize threads for interpreter");
+#endif
+ interp->modules = NULL;
+ interp->modules_reloading = NULL;
+ interp->sysdict = NULL;
+ interp->builtins = NULL;
+ interp->tstate_head = NULL;
+ interp->codec_search_path = NULL;
+ interp->codec_search_cache = NULL;
+ interp->codec_error_registry = NULL;
+#ifdef HAVE_DLOPEN
+#ifdef RTLD_NOW
+ interp->dlopenflags = RTLD_NOW;
+#else
+ interp->dlopenflags = RTLD_LAZY;
+#endif
+#endif
+#ifdef WITH_TSC
+ interp->tscdump = 0;
+#endif
+
+ HEAD_LOCK();
+ interp->next = interp_head;
+ interp_head = interp;
+ HEAD_UNLOCK();
+ }
+
+ return interp;
+}
+
+
+void
+PyInterpreterState_Clear(PyInterpreterState *interp)
+{
+ PyThreadState *p;
+ HEAD_LOCK();
+ for (p = interp->tstate_head; p != NULL; p = p->next)
+ PyThreadState_Clear(p);
+ HEAD_UNLOCK();
+ Py_CLEAR(interp->codec_search_path);
+ Py_CLEAR(interp->codec_search_cache);
+ Py_CLEAR(interp->codec_error_registry);
+ Py_CLEAR(interp->modules);
+ Py_CLEAR(interp->modules_reloading);
+ Py_CLEAR(interp->sysdict);
+ Py_CLEAR(interp->builtins);
+}
+
+
+static void
+zapthreads(PyInterpreterState *interp)
+{
+ PyThreadState *p;
+ /* No need to lock the mutex here because this should only happen
+ when the threads are all really dead (XXX famous last words). */
+ while ((p = interp->tstate_head) != NULL) {
+ PyThreadState_Delete(p);
+ }
+}
+
+
+void
+PyInterpreterState_Delete(PyInterpreterState *interp)
+{
+ PyInterpreterState **p;
+ zapthreads(interp);
+ HEAD_LOCK();
+ for (p = &interp_head; ; p = &(*p)->next) {
+ if (*p == NULL)
+ Py_FatalError(
+ "PyInterpreterState_Delete: invalid interp");
+ if (*p == interp)
+ break;
+ }
+ if (interp->tstate_head != NULL)
+ Py_FatalError("PyInterpreterState_Delete: remaining threads");
+ *p = interp->next;
+ HEAD_UNLOCK();
+ free(interp);
+}
+
+
+/* Default implementation for _PyThreadState_GetFrame */
+static struct _frame *
+threadstate_getframe(PyThreadState *self)
+{
+ return self->frame;
+}
+
+static PyThreadState *
+new_threadstate(PyInterpreterState *interp, int init)
+{
+ PyThreadState *tstate = (PyThreadState *)malloc(sizeof(PyThreadState));
+
+ if (_PyThreadState_GetFrame == NULL)
+ _PyThreadState_GetFrame = threadstate_getframe;
+
+ if (tstate != NULL) {
+ tstate->interp = interp;
+
+ tstate->frame = NULL;
+ tstate->recursion_depth = 0;
+ tstate->tracing = 0;
+ tstate->use_tracing = 0;
+ tstate->tick_counter = 0;
+ tstate->gilstate_counter = 0;
+ tstate->async_exc = NULL;
+#ifdef WITH_THREAD
+ tstate->thread_id = PyThread_get_thread_ident();
+#else
+ tstate->thread_id = 0;
+#endif
+
+ tstate->dict = NULL;
+
+ tstate->curexc_type = NULL;
+ tstate->curexc_value = NULL;
+ tstate->curexc_traceback = NULL;
+
+ tstate->exc_type = NULL;
+ tstate->exc_value = NULL;
+ tstate->exc_traceback = NULL;
+
+ tstate->c_profilefunc = NULL;
+ tstate->c_tracefunc = NULL;
+ tstate->c_profileobj = NULL;
+ tstate->c_traceobj = NULL;
+
+ tstate->trash_delete_nesting = 0;
+ tstate->trash_delete_later = NULL;
+
+ if (init)
+ _PyThreadState_Init(tstate);
+
+ HEAD_LOCK();
+ tstate->next = interp->tstate_head;
+ interp->tstate_head = tstate;
+ HEAD_UNLOCK();
+ }
+
+ return tstate;
+}
+
+PyThreadState *
+PyThreadState_New(PyInterpreterState *interp)
+{
+ return new_threadstate(interp, 1);
+}
+
+PyThreadState *
+_PyThreadState_Prealloc(PyInterpreterState *interp)
+{
+ return new_threadstate(interp, 0);
+}
+
+void
+_PyThreadState_Init(PyThreadState *tstate)
+{
+#ifdef WITH_THREAD
+ _PyGILState_NoteThreadState(tstate);
+#endif
+}
+
+void
+PyThreadState_Clear(PyThreadState *tstate)
+{
+ if (Py_VerboseFlag && tstate->frame != NULL)
+ fprintf(stderr,
+ "PyThreadState_Clear: warning: thread still has a frame\n");
+
+ Py_CLEAR(tstate->frame);
+
+ Py_CLEAR(tstate->dict);
+ Py_CLEAR(tstate->async_exc);
+
+ Py_CLEAR(tstate->curexc_type);
+ Py_CLEAR(tstate->curexc_value);
+ Py_CLEAR(tstate->curexc_traceback);
+
+ Py_CLEAR(tstate->exc_type);
+ Py_CLEAR(tstate->exc_value);
+ Py_CLEAR(tstate->exc_traceback);
+
+ tstate->c_profilefunc = NULL;
+ tstate->c_tracefunc = NULL;
+ Py_CLEAR(tstate->c_profileobj);
+ Py_CLEAR(tstate->c_traceobj);
+}
+
+
+/* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */
+static void
+tstate_delete_common(PyThreadState *tstate)
+{
+ PyInterpreterState *interp;
+ PyThreadState **p;
+ PyThreadState *prev_p = NULL;
+ if (tstate == NULL)
+ Py_FatalError("PyThreadState_Delete: NULL tstate");
+ interp = tstate->interp;
+ if (interp == NULL)
+ Py_FatalError("PyThreadState_Delete: NULL interp");
+ HEAD_LOCK();
+ for (p = &interp->tstate_head; ; p = &(*p)->next) {
+ if (*p == NULL)
+ Py_FatalError(
+ "PyThreadState_Delete: invalid tstate");
+ if (*p == tstate)
+ break;
+ /* Sanity check. These states should never happen but if
+ * they do we must abort. Otherwise we'll end up spinning in
+ * in a tight loop with the lock held. A similar check is done
+ * in thread.c find_key(). */
+ if (*p == prev_p)
+ Py_FatalError(
+ "PyThreadState_Delete: small circular list(!)"
+ " and tstate not found.");
+ prev_p = *p;
+ if ((*p)->next == interp->tstate_head)
+ Py_FatalError(
+ "PyThreadState_Delete: circular list(!) and"
+ " tstate not found.");
+ }
+ *p = tstate->next;
+ HEAD_UNLOCK();
+ free(tstate);
+}
+
+
+void
+PyThreadState_Delete(PyThreadState *tstate)
+{
+ if (tstate == _PyThreadState_Current)
+ Py_FatalError("PyThreadState_Delete: tstate is still current");
+ tstate_delete_common(tstate);
+#ifdef WITH_THREAD
+ if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate)
+ PyThread_delete_key_value(autoTLSkey);
+#endif /* WITH_THREAD */
+}
+
+
+#ifdef WITH_THREAD
+void
+PyThreadState_DeleteCurrent()
+{
+ PyThreadState *tstate = _PyThreadState_Current;
+ if (tstate == NULL)
+ Py_FatalError(
+ "PyThreadState_DeleteCurrent: no current tstate");
+ _PyThreadState_Current = NULL;
+ if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate)
+ PyThread_delete_key_value(autoTLSkey);
+ tstate_delete_common(tstate);
+ PyEval_ReleaseLock();
+}
+#endif /* WITH_THREAD */
+
+
+PyThreadState *
+PyThreadState_Get(void)
+{
+ if (_PyThreadState_Current == NULL)
+ Py_FatalError("PyThreadState_Get: no current thread");
+
+ return _PyThreadState_Current;
+}
+
+
+PyThreadState *
+PyThreadState_Swap(PyThreadState *newts)
+{
+ PyThreadState *oldts = _PyThreadState_Current;
+
+ _PyThreadState_Current = newts;
+ /* It should not be possible for more than one thread state
+ to be used for a thread. Check this the best we can in debug
+ builds.
+ */
+#if defined(Py_DEBUG) && defined(WITH_THREAD)
+ if (newts) {
+ /* This can be called from PyEval_RestoreThread(). Similar
+ to it, we need to ensure errno doesn't change.
+ */
+ int err = errno;
+ PyThreadState *check = PyGILState_GetThisThreadState();
+ if (check && check->interp == newts->interp && check != newts)
+ Py_FatalError("Invalid thread state for this thread");
+ errno = err;
+ }
+#endif
+ return oldts;
+}
+
+/* An extension mechanism to store arbitrary additional per-thread state.
+ PyThreadState_GetDict() returns a dictionary that can be used to hold such
+ state; the caller should pick a unique key and store its state there. If
+ PyThreadState_GetDict() returns NULL, an exception has *not* been raised
+ and the caller should assume no per-thread state is available. */
+
+PyObject *
+PyThreadState_GetDict(void)
+{
+ if (_PyThreadState_Current == NULL)
+ return NULL;
+
+ if (_PyThreadState_Current->dict == NULL) {
+ PyObject *d;
+ _PyThreadState_Current->dict = d = PyDict_New();
+ if (d == NULL)
+ PyErr_Clear();
+ }
+ return _PyThreadState_Current->dict;
+}
+
+
+/* Asynchronously raise an exception in a thread.
+ Requested by Just van Rossum and Alex Martelli.
+ To prevent naive misuse, you must write your own extension
+ to call this, or use ctypes. Must be called with the GIL held.
+ Returns the number of tstates modified (normally 1, but 0 if `id` didn't
+ match any known thread id). Can be called with exc=NULL to clear an
+ existing async exception. This raises no exceptions. */
+
+int
+PyThreadState_SetAsyncExc(long id, PyObject *exc) {
+ PyThreadState *tstate = PyThreadState_GET();
+ PyInterpreterState *interp = tstate->interp;
+ PyThreadState *p;
+
+ /* Although the GIL is held, a few C API functions can be called
+ * without the GIL held, and in particular some that create and
+ * destroy thread and interpreter states. Those can mutate the
+ * list of thread states we're traversing, so to prevent that we lock
+ * head_mutex for the duration.
+ */
+ HEAD_LOCK();
+ for (p = interp->tstate_head; p != NULL; p = p->next) {
+ if (p->thread_id == id) {
+ /* Tricky: we need to decref the current value
+ * (if any) in p->async_exc, but that can in turn
+ * allow arbitrary Python code to run, including
+ * perhaps calls to this function. To prevent
+ * deadlock, we need to release head_mutex before
+ * the decref.
+ */
+ PyObject *old_exc = p->async_exc;
+ Py_XINCREF(exc);
+ p->async_exc = exc;
+ HEAD_UNLOCK();
+ Py_XDECREF(old_exc);
+ return 1;
+ }
+ }
+ HEAD_UNLOCK();
+ return 0;
+}
+
+
+/* Routines for advanced debuggers, requested by David Beazley.
+ Don't use unless you know what you are doing! */
+
+PyInterpreterState *
+PyInterpreterState_Head(void)
+{
+ return interp_head;
+}
+
+PyInterpreterState *
+PyInterpreterState_Next(PyInterpreterState *interp) {
+ return interp->next;
+}
+
+PyThreadState *
+PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
+ return interp->tstate_head;
+}
+
+PyThreadState *
+PyThreadState_Next(PyThreadState *tstate) {
+ return tstate->next;
+}
+
+/* The implementation of sys._current_frames(). This is intended to be
+ called with the GIL held, as it will be when called via
+ sys._current_frames(). It's possible it would work fine even without
+ the GIL held, but haven't thought enough about that.
+*/
+PyObject *
+_PyThread_CurrentFrames(void)
+{
+ PyObject *result;
+ PyInterpreterState *i;
+
+ result = PyDict_New();
+ if (result == NULL)
+ return NULL;
+
+ /* for i in all interpreters:
+ * for t in all of i's thread states:
+ * if t's frame isn't NULL, map t's id to its frame
+ * Because these lists can mutate even when the GIL is held, we
+ * need to grab head_mutex for the duration.
+ */
+ HEAD_LOCK();
+ for (i = interp_head; i != NULL; i = i->next) {
+ PyThreadState *t;
+ for (t = i->tstate_head; t != NULL; t = t->next) {
+ PyObject *id;
+ int stat;
+ struct _frame *frame = t->frame;
+ if (frame == NULL)
+ continue;
+ id = PyInt_FromLong(t->thread_id);
+ if (id == NULL)
+ goto Fail;
+ stat = PyDict_SetItem(result, id, (PyObject *)frame);
+ Py_DECREF(id);
+ if (stat < 0)
+ goto Fail;
+ }
+ }
+ HEAD_UNLOCK();
+ return result;
+
+ Fail:
+ HEAD_UNLOCK();
+ Py_DECREF(result);
+ return NULL;
+}
+
+/* Python "auto thread state" API. */
+#ifdef WITH_THREAD
+
+/* Keep this as a static, as it is not reliable! It can only
+ ever be compared to the state for the *current* thread.
+ * If not equal, then it doesn't matter that the actual
+ value may change immediately after comparison, as it can't
+ possibly change to the current thread's state.
+ * If equal, then the current thread holds the lock, so the value can't
+ change until we yield the lock.
+*/
+static int
+PyThreadState_IsCurrent(PyThreadState *tstate)
+{
+ /* Must be the tstate for this thread */
+ assert(PyGILState_GetThisThreadState()==tstate);
+ /* On Windows at least, simple reads and writes to 32 bit values
+ are atomic.
+ */
+ return tstate == _PyThreadState_Current;
+}
+
+/* Internal initialization/finalization functions called by
+ Py_Initialize/Py_Finalize
+*/
+void
+_PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
+{
+ assert(i && t); /* must init with valid states */
+ autoTLSkey = PyThread_create_key();
+ autoInterpreterState = i;
+ assert(PyThread_get_key_value(autoTLSkey) == NULL);
+ assert(t->gilstate_counter == 0);
+
+ _PyGILState_NoteThreadState(t);
+}
+
+void
+_PyGILState_Fini(void)
+{
+ PyThread_delete_key(autoTLSkey);
+ autoInterpreterState = NULL;
+}
+
+/* When a thread state is created for a thread by some mechanism other than
+ PyGILState_Ensure, it's important that the GILState machinery knows about
+ it so it doesn't try to create another thread state for the thread (this is
+ a better fix for SF bug #1010677 than the first one attempted).
+*/
+static void
+_PyGILState_NoteThreadState(PyThreadState* tstate)
+{
+ /* If autoTLSkey isn't initialized, this must be the very first
+ threadstate created in Py_Initialize(). Don't do anything for now
+ (we'll be back here when _PyGILState_Init is called). */
+ if (!autoInterpreterState)
+ return;
+
+ /* Stick the thread state for this thread in thread local storage.
+
+ The only situation where you can legitimately have more than one
+ thread state for an OS level thread is when there are multiple
+ interpreters, when:
+
+ a) You shouldn't really be using the PyGILState_ APIs anyway,
+ and:
+
+ b) The slightly odd way PyThread_set_key_value works (see
+ comments by its implementation) means that the first thread
+ state created for that given OS level thread will "win",
+ which seems reasonable behaviour.
+ */
+ if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0)
+ Py_FatalError("Couldn't create autoTLSkey mapping");
+
+ /* PyGILState_Release must not try to delete this thread state. */
+ tstate->gilstate_counter = 1;
+}
+
+/* The public functions */
+PyThreadState *
+PyGILState_GetThisThreadState(void)
+{
+ if (autoInterpreterState == NULL)
+ return NULL;
+ return (PyThreadState *)PyThread_get_key_value(autoTLSkey);
+}
+
+PyGILState_STATE
+PyGILState_Ensure(void)
+{
+ int current;
+ PyThreadState *tcur;
+ int need_init_threads = 0;
+
+ /* Note that we do not auto-init Python here - apart from
+ potential races with 2 threads auto-initializing, pep-311
+ spells out other issues. Embedders are expected to have
+ called Py_Initialize() and usually PyEval_InitThreads().
+ */
+ assert(autoInterpreterState); /* Py_Initialize() hasn't been called! */
+ tcur = (PyThreadState *)PyThread_get_key_value(autoTLSkey);
+ if (tcur == NULL) {
+ need_init_threads = 1;
+
+ /* Create a new thread state for this thread */
+ tcur = PyThreadState_New(autoInterpreterState);
+ if (tcur == NULL)
+ Py_FatalError("Couldn't create thread-state for new thread");
+ /* This is our thread state! We'll need to delete it in the
+ matching call to PyGILState_Release(). */
+ tcur->gilstate_counter = 0;
+ current = 0; /* new thread state is never current */
+ }
+ else {
+ current = PyThreadState_IsCurrent(tcur);
+ }
+
+ if (current == 0) {
+ PyEval_RestoreThread(tcur);
+ }
+
+ /* Update our counter in the thread-state - no need for locks:
+ - tcur will remain valid as we hold the GIL.
+ - the counter is safe as we are the only thread "allowed"
+ to modify this value
+ */
+ ++tcur->gilstate_counter;
+
+ if (need_init_threads) {
+ /* At startup, Python has no concrete GIL. If PyGILState_Ensure() is
+ called from a new thread for the first time, we need the create the
+ GIL. */
+ PyEval_InitThreads();
+ }
+
+ return current ? PyGILState_LOCKED : PyGILState_UNLOCKED;
+}
+
+void
+PyGILState_Release(PyGILState_STATE oldstate)
+{
+ PyThreadState *tcur = (PyThreadState *)PyThread_get_key_value(
+ autoTLSkey);
+ if (tcur == NULL)
+ Py_FatalError("auto-releasing thread-state, "
+ "but no thread-state for this thread");
+ /* We must hold the GIL and have our thread state current */
+ /* XXX - remove the check - the assert should be fine,
+ but while this is very new (April 2003), the extra check
+ by release-only users can't hurt.
+ */
+ if (! PyThreadState_IsCurrent(tcur))
+ Py_FatalError("This thread state must be current when releasing");
+ assert(PyThreadState_IsCurrent(tcur));
+ --tcur->gilstate_counter;
+ assert(tcur->gilstate_counter >= 0); /* illegal counter value */
+
+ /* If we're going to destroy this thread-state, we must
+ * clear it while the GIL is held, as destructors may run.
+ */
+ if (tcur->gilstate_counter == 0) {
+ /* can't have been locked when we created it */
+ assert(oldstate == PyGILState_UNLOCKED);
+ PyThreadState_Clear(tcur);
+ /* Delete the thread-state. Note this releases the GIL too!
+ * It's vital that the GIL be held here, to avoid shutdown
+ * races; see bugs 225673 and 1061968 (that nasty bug has a
+ * habit of coming back).
+ */
+ PyThreadState_DeleteCurrent();
+ }
+ /* Release the lock if necessary */
+ else if (oldstate == PyGILState_UNLOCKED)
+ PyEval_SaveThread();
+}
+
+#endif /* WITH_THREAD */
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/contrib/tools/python/src/Python/pystrcmp.c b/contrib/tools/python/src/Python/pystrcmp.c
new file mode 100644
index 0000000000..f9c2277cb5
--- /dev/null
+++ b/contrib/tools/python/src/Python/pystrcmp.c
@@ -0,0 +1,26 @@
+/* Cross platform case insensitive string compare functions
+ */
+
+#include "Python.h"
+
+int
+PyOS_mystrnicmp(const char *s1, const char *s2, Py_ssize_t size)
+{
+ if (size == 0)
+ return 0;
+ while ((--size > 0) &&
+ (tolower((unsigned)*s1) == tolower((unsigned)*s2))) {
+ if (!*s1++ || !*s2++)
+ break;
+ }
+ return tolower((unsigned)*s1) - tolower((unsigned)*s2);
+}
+
+int
+PyOS_mystricmp(const char *s1, const char *s2)
+{
+ while (*s1 && (tolower((unsigned)*s1++) == tolower((unsigned)*s2++))) {
+ ;
+ }
+ return (tolower((unsigned)*s1) - tolower((unsigned)*s2));
+}
diff --git a/contrib/tools/python/src/Python/pystrtod.c b/contrib/tools/python/src/Python/pystrtod.c
new file mode 100644
index 0000000000..29d79960ab
--- /dev/null
+++ b/contrib/tools/python/src/Python/pystrtod.c
@@ -0,0 +1,1247 @@
+/* -*- Mode: C; c-file-style: "python" -*- */
+
+#include <Python.h>
+#include <locale.h>
+
+/* Case-insensitive string match used for nan and inf detection; t should be
+ lower-case. Returns 1 for a successful match, 0 otherwise. */
+
+static int
+case_insensitive_match(const char *s, const char *t)
+{
+ while(*t && Py_TOLOWER(*s) == *t) {
+ s++;
+ t++;
+ }
+ return *t ? 0 : 1;
+}
+
+/* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or
+ "infinity", with an optional leading sign of "+" or "-". On success,
+ return the NaN or Infinity as a double and set *endptr to point just beyond
+ the successfully parsed portion of the string. On failure, return -1.0 and
+ set *endptr to point to the start of the string. */
+
+double
+_Py_parse_inf_or_nan(const char *p, char **endptr)
+{
+ double retval;
+ const char *s;
+ int negate = 0;
+
+ s = p;
+ if (*s == '-') {
+ negate = 1;
+ s++;
+ }
+ else if (*s == '+') {
+ s++;
+ }
+ if (case_insensitive_match(s, "inf")) {
+ s += 3;
+ if (case_insensitive_match(s, "inity"))
+ s += 5;
+ retval = negate ? -Py_HUGE_VAL : Py_HUGE_VAL;
+ }
+#ifdef Py_NAN
+ else if (case_insensitive_match(s, "nan")) {
+ s += 3;
+ retval = negate ? -Py_NAN : Py_NAN;
+ }
+#endif
+ else {
+ s = p;
+ retval = -1.0;
+ }
+ *endptr = (char *)s;
+ return retval;
+}
+
+/**
+ * PyOS_ascii_strtod:
+ * @nptr: the string to convert to a numeric value.
+ * @endptr: if non-%NULL, it returns the character after
+ * the last character used in the conversion.
+ *
+ * Converts a string to a #gdouble value.
+ * This function behaves like the standard strtod() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtod() function.
+ *
+ * If the correct value would cause overflow, plus or minus %HUGE_VAL
+ * is returned (according to the sign of the value), and %ERANGE is
+ * stored in %errno. If the correct value would cause underflow,
+ * zero is returned and %ERANGE is stored in %errno.
+ * If memory allocation fails, %ENOMEM is stored in %errno.
+ *
+ * This function resets %errno before calling strtod() so that
+ * you can reliably detect overflow and underflow.
+ *
+ * Return value: the #gdouble value.
+ **/
+
+#ifndef PY_NO_SHORT_FLOAT_REPR
+
+double
+_PyOS_ascii_strtod(const char *nptr, char **endptr)
+{
+ double result;
+ _Py_SET_53BIT_PRECISION_HEADER;
+
+ assert(nptr != NULL);
+ /* Set errno to zero, so that we can distinguish zero results
+ and underflows */
+ errno = 0;
+
+ _Py_SET_53BIT_PRECISION_START;
+ result = _Py_dg_strtod(nptr, endptr);
+ _Py_SET_53BIT_PRECISION_END;
+
+ if (*endptr == nptr)
+ /* string might represent an inf or nan */
+ result = _Py_parse_inf_or_nan(nptr, endptr);
+
+ return result;
+
+}
+
+#else
+
+/*
+ Use system strtod; since strtod is locale aware, we may
+ have to first fix the decimal separator.
+
+ Note that unlike _Py_dg_strtod, the system strtod may not always give
+ correctly rounded results.
+*/
+
+double
+_PyOS_ascii_strtod(const char *nptr, char **endptr)
+{
+ char *fail_pos;
+ double val = -1.0;
+ struct lconv *locale_data;
+ const char *decimal_point;
+ size_t decimal_point_len;
+ const char *p, *decimal_point_pos;
+ const char *end = NULL; /* Silence gcc */
+ const char *digits_pos = NULL;
+ int negate = 0;
+
+ assert(nptr != NULL);
+
+ fail_pos = NULL;
+
+ locale_data = localeconv();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen(decimal_point);
+
+ assert(decimal_point_len != 0);
+
+ decimal_point_pos = NULL;
+
+ /* Parse infinities and nans */
+ val = _Py_parse_inf_or_nan(nptr, endptr);
+ if (*endptr != nptr)
+ return val;
+
+ /* Set errno to zero, so that we can distinguish zero results
+ and underflows */
+ errno = 0;
+
+ /* We process the optional sign manually, then pass the remainder to
+ the system strtod. This ensures that the result of an underflow
+ has the correct sign. (bug #1725) */
+ p = nptr;
+ /* Process leading sign, if present */
+ if (*p == '-') {
+ negate = 1;
+ p++;
+ }
+ else if (*p == '+') {
+ p++;
+ }
+
+ /* Some platform strtods accept hex floats; Python shouldn't (at the
+ moment), so we check explicitly for strings starting with '0x'. */
+ if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X'))
+ goto invalid_string;
+
+ /* Check that what's left begins with a digit or decimal point */
+ if (!Py_ISDIGIT(*p) && *p != '.')
+ goto invalid_string;
+
+ digits_pos = p;
+ if (decimal_point[0] != '.' ||
+ decimal_point[1] != 0)
+ {
+ /* Look for a '.' in the input; if present, it'll need to be
+ swapped for the current locale's decimal point before we
+ call strtod. On the other hand, if we find the current
+ locale's decimal point then the input is invalid. */
+ while (Py_ISDIGIT(*p))
+ p++;
+
+ if (*p == '.')
+ {
+ decimal_point_pos = p++;
+
+ /* locate end of number */
+ while (Py_ISDIGIT(*p))
+ p++;
+
+ if (*p == 'e' || *p == 'E')
+ p++;
+ if (*p == '+' || *p == '-')
+ p++;
+ while (Py_ISDIGIT(*p))
+ p++;
+ end = p;
+ }
+ else if (strncmp(p, decimal_point, decimal_point_len) == 0)
+ /* Python bug #1417699 */
+ goto invalid_string;
+ /* For the other cases, we need not convert the decimal
+ point */
+ }
+
+ if (decimal_point_pos) {
+ char *copy, *c;
+ /* Create a copy of the input, with the '.' converted to the
+ locale-specific decimal point */
+ copy = (char *)PyMem_MALLOC(end - digits_pos +
+ 1 + decimal_point_len);
+ if (copy == NULL) {
+ *endptr = (char *)nptr;
+ errno = ENOMEM;
+ return val;
+ }
+
+ c = copy;
+ memcpy(c, digits_pos, decimal_point_pos - digits_pos);
+ c += decimal_point_pos - digits_pos;
+ memcpy(c, decimal_point, decimal_point_len);
+ c += decimal_point_len;
+ memcpy(c, decimal_point_pos + 1,
+ end - (decimal_point_pos + 1));
+ c += end - (decimal_point_pos + 1);
+ *c = 0;
+
+ val = strtod(copy, &fail_pos);
+
+ if (fail_pos)
+ {
+ if (fail_pos > decimal_point_pos)
+ fail_pos = (char *)digits_pos +
+ (fail_pos - copy) -
+ (decimal_point_len - 1);
+ else
+ fail_pos = (char *)digits_pos +
+ (fail_pos - copy);
+ }
+
+ PyMem_FREE(copy);
+
+ }
+ else {
+ val = strtod(digits_pos, &fail_pos);
+ }
+
+ if (fail_pos == digits_pos)
+ goto invalid_string;
+
+ if (negate && fail_pos != nptr)
+ val = -val;
+ *endptr = fail_pos;
+
+ return val;
+
+ invalid_string:
+ *endptr = (char*)nptr;
+ errno = EINVAL;
+ return -1.0;
+}
+
+#endif
+
+/* PyOS_ascii_strtod is DEPRECATED in Python 2.7 and 3.1 */
+
+double
+PyOS_ascii_strtod(const char *nptr, char **endptr)
+{
+ char *fail_pos;
+ const char *p;
+ double x;
+
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "PyOS_ascii_strtod and PyOS_ascii_atof are "
+ "deprecated. Use PyOS_string_to_double "
+ "instead.", 1) < 0)
+ return -1.0;
+
+ /* _PyOS_ascii_strtod already does everything that we want,
+ except that it doesn't parse leading whitespace */
+ p = nptr;
+ while (Py_ISSPACE(*p))
+ p++;
+ x = _PyOS_ascii_strtod(p, &fail_pos);
+ if (fail_pos == p)
+ fail_pos = (char *)nptr;
+ if (endptr)
+ *endptr = (char *)fail_pos;
+ return x;
+}
+
+/* PyOS_ascii_strtod is DEPRECATED in Python 2.7 and 3.1 */
+
+double
+PyOS_ascii_atof(const char *nptr)
+{
+ return PyOS_ascii_strtod(nptr, NULL);
+}
+
+/* PyOS_string_to_double is the recommended replacement for the deprecated
+ PyOS_ascii_strtod and PyOS_ascii_atof functions. It converts a
+ null-terminated byte string s (interpreted as a string of ASCII characters)
+ to a float. The string should not have leading or trailing whitespace (in
+ contrast, PyOS_ascii_strtod allows leading whitespace but not trailing
+ whitespace). The conversion is independent of the current locale.
+
+ If endptr is NULL, try to convert the whole string. Raise ValueError and
+ return -1.0 if the string is not a valid representation of a floating-point
+ number.
+
+ If endptr is non-NULL, try to convert as much of the string as possible.
+ If no initial segment of the string is the valid representation of a
+ floating-point number then *endptr is set to point to the beginning of the
+ string, -1.0 is returned and again ValueError is raised.
+
+ On overflow (e.g., when trying to convert '1e500' on an IEEE 754 machine),
+ if overflow_exception is NULL then +-Py_HUGE_VAL is returned, and no Python
+ exception is raised. Otherwise, overflow_exception should point to
+ a Python exception, this exception will be raised, -1.0 will be returned,
+ and *endptr will point just past the end of the converted value.
+
+ If any other failure occurs (for example lack of memory), -1.0 is returned
+ and the appropriate Python exception will have been set.
+*/
+
+double
+PyOS_string_to_double(const char *s,
+ char **endptr,
+ PyObject *overflow_exception)
+{
+ double x, result=-1.0;
+ char *fail_pos;
+
+ errno = 0;
+ PyFPE_START_PROTECT("PyOS_string_to_double", return -1.0)
+ x = _PyOS_ascii_strtod(s, &fail_pos);
+ PyFPE_END_PROTECT(x)
+
+ if (errno == ENOMEM) {
+ PyErr_NoMemory();
+ fail_pos = (char *)s;
+ }
+ else if (!endptr && (fail_pos == s || *fail_pos != '\0'))
+ PyErr_Format(PyExc_ValueError,
+ "could not convert string to float: "
+ "%.200s", s);
+ else if (fail_pos == s)
+ PyErr_Format(PyExc_ValueError,
+ "could not convert string to float: "
+ "%.200s", s);
+ else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception)
+ PyErr_Format(overflow_exception,
+ "value too large to convert to float: "
+ "%.200s", s);
+ else
+ result = x;
+
+ if (endptr != NULL)
+ *endptr = fail_pos;
+ return result;
+}
+
+/* Given a string that may have a decimal point in the current
+ locale, change it back to a dot. Since the string cannot get
+ longer, no need for a maximum buffer size parameter. */
+Py_LOCAL_INLINE(void)
+change_decimal_from_locale_to_dot(char* buffer)
+{
+ struct lconv *locale_data = localeconv();
+ const char *decimal_point = locale_data->decimal_point;
+
+ if (decimal_point[0] != '.' || decimal_point[1] != 0) {
+ size_t decimal_point_len = strlen(decimal_point);
+
+ if (*buffer == '+' || *buffer == '-')
+ buffer++;
+ while (Py_ISDIGIT(*buffer))
+ buffer++;
+ if (strncmp(buffer, decimal_point, decimal_point_len) == 0) {
+ *buffer = '.';
+ buffer++;
+ if (decimal_point_len > 1) {
+ /* buffer needs to get smaller */
+ size_t rest_len = strlen(buffer +
+ (decimal_point_len - 1));
+ memmove(buffer,
+ buffer + (decimal_point_len - 1),
+ rest_len);
+ buffer[rest_len] = 0;
+ }
+ }
+ }
+}
+
+
+/* From the C99 standard, section 7.19.6:
+The exponent always contains at least two digits, and only as many more digits
+as necessary to represent the exponent.
+*/
+#define MIN_EXPONENT_DIGITS 2
+
+/* Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS
+ in length. */
+Py_LOCAL_INLINE(void)
+ensure_minimum_exponent_length(char* buffer, size_t buf_size)
+{
+ char *p = strpbrk(buffer, "eE");
+ if (p && (*(p + 1) == '-' || *(p + 1) == '+')) {
+ char *start = p + 2;
+ int exponent_digit_cnt = 0;
+ int leading_zero_cnt = 0;
+ int in_leading_zeros = 1;
+ int significant_digit_cnt;
+
+ /* Skip over the exponent and the sign. */
+ p += 2;
+
+ /* Find the end of the exponent, keeping track of leading
+ zeros. */
+ while (*p && Py_ISDIGIT(*p)) {
+ if (in_leading_zeros && *p == '0')
+ ++leading_zero_cnt;
+ if (*p != '0')
+ in_leading_zeros = 0;
+ ++p;
+ ++exponent_digit_cnt;
+ }
+
+ significant_digit_cnt = exponent_digit_cnt - leading_zero_cnt;
+ if (exponent_digit_cnt == MIN_EXPONENT_DIGITS) {
+ /* If there are 2 exactly digits, we're done,
+ regardless of what they contain */
+ }
+ else if (exponent_digit_cnt > MIN_EXPONENT_DIGITS) {
+ int extra_zeros_cnt;
+
+ /* There are more than 2 digits in the exponent. See
+ if we can delete some of the leading zeros */
+ if (significant_digit_cnt < MIN_EXPONENT_DIGITS)
+ significant_digit_cnt = MIN_EXPONENT_DIGITS;
+ extra_zeros_cnt = exponent_digit_cnt -
+ significant_digit_cnt;
+
+ /* Delete extra_zeros_cnt worth of characters from the
+ front of the exponent */
+ assert(extra_zeros_cnt >= 0);
+
+ /* Add one to significant_digit_cnt to copy the
+ trailing 0 byte, thus setting the length */
+ memmove(start,
+ start + extra_zeros_cnt,
+ significant_digit_cnt + 1);
+ }
+ else {
+ /* If there are fewer than 2 digits, add zeros
+ until there are 2, if there's enough room */
+ int zeros = MIN_EXPONENT_DIGITS - exponent_digit_cnt;
+ if (start + zeros + exponent_digit_cnt + 1
+ < buffer + buf_size) {
+ memmove(start + zeros, start,
+ exponent_digit_cnt + 1);
+ memset(start, '0', zeros);
+ }
+ }
+ }
+}
+
+/* Remove trailing zeros after the decimal point from a numeric string; also
+ remove the decimal point if all digits following it are zero. The numeric
+ string must end in '\0', and should not have any leading or trailing
+ whitespace. Assumes that the decimal point is '.'. */
+Py_LOCAL_INLINE(void)
+remove_trailing_zeros(char *buffer)
+{
+ char *old_fraction_end, *new_fraction_end, *end, *p;
+
+ p = buffer;
+ if (*p == '-' || *p == '+')
+ /* Skip leading sign, if present */
+ ++p;
+ while (Py_ISDIGIT(*p))
+ ++p;
+
+ /* if there's no decimal point there's nothing to do */
+ if (*p++ != '.')
+ return;
+
+ /* scan any digits after the point */
+ while (Py_ISDIGIT(*p))
+ ++p;
+ old_fraction_end = p;
+
+ /* scan up to ending '\0' */
+ while (*p != '\0')
+ p++;
+ /* +1 to make sure that we move the null byte as well */
+ end = p+1;
+
+ /* scan back from fraction_end, looking for removable zeros */
+ p = old_fraction_end;
+ while (*(p-1) == '0')
+ --p;
+ /* and remove point if we've got that far */
+ if (*(p-1) == '.')
+ --p;
+ new_fraction_end = p;
+
+ memmove(new_fraction_end, old_fraction_end, end-old_fraction_end);
+}
+
+/* Ensure that buffer has a decimal point in it. The decimal point will not
+ be in the current locale, it will always be '.'. Don't add a decimal point
+ if an exponent is present. Also, convert to exponential notation where
+ adding a '.0' would produce too many significant digits (see issue 5864).
+
+ Returns a pointer to the fixed buffer, or NULL on failure.
+*/
+Py_LOCAL_INLINE(char *)
+ensure_decimal_point(char* buffer, size_t buf_size, int precision)
+{
+ int digit_count, insert_count = 0, convert_to_exp = 0;
+ char *chars_to_insert, *digits_start;
+
+ /* search for the first non-digit character */
+ char *p = buffer;
+ if (*p == '-' || *p == '+')
+ /* Skip leading sign, if present. I think this could only
+ ever be '-', but it can't hurt to check for both. */
+ ++p;
+ digits_start = p;
+ while (*p && Py_ISDIGIT(*p))
+ ++p;
+ digit_count = Py_SAFE_DOWNCAST(p - digits_start, Py_ssize_t, int);
+
+ if (*p == '.') {
+ if (Py_ISDIGIT(*(p+1))) {
+ /* Nothing to do, we already have a decimal
+ point and a digit after it */
+ }
+ else {
+ /* We have a decimal point, but no following
+ digit. Insert a zero after the decimal. */
+ /* can't ever get here via PyOS_double_to_string */
+ assert(precision == -1);
+ ++p;
+ chars_to_insert = "0";
+ insert_count = 1;
+ }
+ }
+ else if (!(*p == 'e' || *p == 'E')) {
+ /* Don't add ".0" if we have an exponent. */
+ if (digit_count == precision) {
+ /* issue 5864: don't add a trailing .0 in the case
+ where the '%g'-formatted result already has as many
+ significant digits as were requested. Switch to
+ exponential notation instead. */
+ convert_to_exp = 1;
+ /* no exponent, no point, and we shouldn't land here
+ for infs and nans, so we must be at the end of the
+ string. */
+ assert(*p == '\0');
+ }
+ else {
+ assert(precision == -1 || digit_count < precision);
+ chars_to_insert = ".0";
+ insert_count = 2;
+ }
+ }
+ if (insert_count) {
+ size_t buf_len = strlen(buffer);
+ if (buf_len + insert_count + 1 >= buf_size) {
+ /* If there is not enough room in the buffer
+ for the additional text, just skip it. It's
+ not worth generating an error over. */
+ }
+ else {
+ memmove(p + insert_count, p,
+ buffer + strlen(buffer) - p + 1);
+ memcpy(p, chars_to_insert, insert_count);
+ }
+ }
+ if (convert_to_exp) {
+ int written;
+ size_t buf_avail;
+ p = digits_start;
+ /* insert decimal point */
+ assert(digit_count >= 1);
+ memmove(p+2, p+1, digit_count); /* safe, but overwrites nul */
+ p[1] = '.';
+ p += digit_count+1;
+ assert(p <= buf_size+buffer);
+ buf_avail = buf_size+buffer-p;
+ if (buf_avail == 0)
+ return NULL;
+ /* Add exponent. It's okay to use lower case 'e': we only
+ arrive here as a result of using the empty format code or
+ repr/str builtins and those never want an upper case 'E' */
+ written = PyOS_snprintf(p, buf_avail, "e%+.02d", digit_count-1);
+ if (!(0 <= written &&
+ written < Py_SAFE_DOWNCAST(buf_avail, size_t, int)))
+ /* output truncated, or something else bad happened */
+ return NULL;
+ remove_trailing_zeros(buffer);
+ }
+ return buffer;
+}
+
+/* see FORMATBUFLEN in unicodeobject.c */
+#define FLOAT_FORMATBUFLEN 120
+
+/**
+ * PyOS_ascii_formatd:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_size: The length of the buffer.
+ * @format: The printf()-style format to use for the
+ * code to use for converting.
+ * @d: The #gdouble to convert
+ *
+ * Converts a #gdouble to a string, using the '.' as
+ * decimal point. To format the number you pass in
+ * a printf()-style format string. Allowed conversion
+ * specifiers are 'e', 'E', 'f', 'F', 'g', 'G', and 'Z'.
+ *
+ * 'Z' is the same as 'g', except it always has a decimal and
+ * at least one digit after the decimal.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ * On failure returns NULL but does not set any Python exception.
+ **/
+char *
+_PyOS_ascii_formatd(char *buffer,
+ size_t buf_size,
+ const char *format,
+ double d,
+ int precision)
+{
+ char format_char;
+ size_t format_len = strlen(format);
+
+ /* Issue 2264: code 'Z' requires copying the format. 'Z' is 'g', but
+ also with at least one character past the decimal. */
+ char tmp_format[FLOAT_FORMATBUFLEN];
+
+ /* The last character in the format string must be the format char */
+ format_char = format[format_len - 1];
+
+ if (format[0] != '%')
+ return NULL;
+
+ /* I'm not sure why this test is here. It's ensuring that the format
+ string after the first character doesn't have a single quote, a
+ lowercase l, or a percent. This is the reverse of the commented-out
+ test about 10 lines ago. */
+ if (strpbrk(format + 1, "'l%"))
+ return NULL;
+
+ /* Also curious about this function is that it accepts format strings
+ like "%xg", which are invalid for floats. In general, the
+ interface to this function is not very good, but changing it is
+ difficult because it's a public API. */
+
+ if (!(format_char == 'e' || format_char == 'E' ||
+ format_char == 'f' || format_char == 'F' ||
+ format_char == 'g' || format_char == 'G' ||
+ format_char == 'Z'))
+ return NULL;
+
+ /* Map 'Z' format_char to 'g', by copying the format string and
+ replacing the final char with a 'g' */
+ if (format_char == 'Z') {
+ if (format_len + 1 >= sizeof(tmp_format)) {
+ /* The format won't fit in our copy. Error out. In
+ practice, this will never happen and will be
+ detected by returning NULL */
+ return NULL;
+ }
+ strcpy(tmp_format, format);
+ tmp_format[format_len - 1] = 'g';
+ format = tmp_format;
+ }
+
+
+ /* Have PyOS_snprintf do the hard work */
+ PyOS_snprintf(buffer, buf_size, format, d);
+
+ /* Do various fixups on the return string */
+
+ /* Get the current locale, and find the decimal point string.
+ Convert that string back to a dot. */
+ change_decimal_from_locale_to_dot(buffer);
+
+ /* If an exponent exists, ensure that the exponent is at least
+ MIN_EXPONENT_DIGITS digits, providing the buffer is large enough
+ for the extra zeros. Also, if there are more than
+ MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get
+ back to MIN_EXPONENT_DIGITS */
+ ensure_minimum_exponent_length(buffer, buf_size);
+
+ /* If format_char is 'Z', make sure we have at least one character
+ after the decimal point (and make sure we have a decimal point);
+ also switch to exponential notation in some edge cases where the
+ extra character would produce more significant digits that we
+ really want. */
+ if (format_char == 'Z')
+ buffer = ensure_decimal_point(buffer, buf_size, precision);
+
+ return buffer;
+}
+
+char *
+PyOS_ascii_formatd(char *buffer,
+ size_t buf_size,
+ const char *format,
+ double d)
+{
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "PyOS_ascii_formatd is deprecated, "
+ "use PyOS_double_to_string instead", 1) < 0)
+ return NULL;
+
+ return _PyOS_ascii_formatd(buffer, buf_size, format, d, -1);
+}
+
+#ifdef PY_NO_SHORT_FLOAT_REPR
+
+/* The fallback code to use if _Py_dg_dtoa is not available. */
+
+PyAPI_FUNC(char *) PyOS_double_to_string(double val,
+ char format_code,
+ int precision,
+ int flags,
+ int *type)
+{
+ char format[32];
+ Py_ssize_t bufsize;
+ char *buf;
+ int t, exp;
+ int upper = 0;
+
+ /* Validate format_code, and map upper and lower case */
+ switch (format_code) {
+ case 'e': /* exponent */
+ case 'f': /* fixed */
+ case 'g': /* general */
+ break;
+ case 'E':
+ upper = 1;
+ format_code = 'e';
+ break;
+ case 'F':
+ upper = 1;
+ format_code = 'f';
+ break;
+ case 'G':
+ upper = 1;
+ format_code = 'g';
+ break;
+ case 'r': /* repr format */
+ /* Supplied precision is unused, must be 0. */
+ if (precision != 0) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ /* The repr() precision (17 significant decimal digits) is the
+ minimal number that is guaranteed to have enough precision
+ so that if the number is read back in the exact same binary
+ value is recreated. This is true for IEEE floating point
+ by design, and also happens to work for all other modern
+ hardware. */
+ precision = 17;
+ format_code = 'g';
+ break;
+ default:
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ /* Here's a quick-and-dirty calculation to figure out how big a buffer
+ we need. In general, for a finite float we need:
+
+ 1 byte for each digit of the decimal significand, and
+
+ 1 for a possible sign
+ 1 for a possible decimal point
+ 2 for a possible [eE][+-]
+ 1 for each digit of the exponent; if we allow 19 digits
+ total then we're safe up to exponents of 2**63.
+ 1 for the trailing nul byte
+
+ This gives a total of 24 + the number of digits in the significand,
+ and the number of digits in the significand is:
+
+ for 'g' format: at most precision, except possibly
+ when precision == 0, when it's 1.
+ for 'e' format: precision+1
+ for 'f' format: precision digits after the point, at least 1
+ before. To figure out how many digits appear before the point
+ we have to examine the size of the number. If fabs(val) < 1.0
+ then there will be only one digit before the point. If
+ fabs(val) >= 1.0, then there are at most
+
+ 1+floor(log10(ceiling(fabs(val))))
+
+ digits before the point (where the 'ceiling' allows for the
+ possibility that the rounding rounds the integer part of val
+ up). A safe upper bound for the above quantity is
+ 1+floor(exp/3), where exp is the unique integer such that 0.5
+ <= fabs(val)/2**exp < 1.0. This exp can be obtained from
+ frexp.
+
+ So we allow room for precision+1 digits for all formats, plus an
+ extra floor(exp/3) digits for 'f' format.
+
+ */
+
+ if (Py_IS_NAN(val) || Py_IS_INFINITY(val))
+ /* 3 for 'inf'/'nan', 1 for sign, 1 for '\0' */
+ bufsize = 5;
+ else {
+ bufsize = 25 + precision;
+ if (format_code == 'f' && fabs(val) >= 1.0) {
+ frexp(val, &exp);
+ bufsize += exp/3;
+ }
+ }
+
+ buf = PyMem_Malloc(bufsize);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ /* Handle nan and inf. */
+ if (Py_IS_NAN(val)) {
+ strcpy(buf, "nan");
+ t = Py_DTST_NAN;
+ } else if (Py_IS_INFINITY(val)) {
+ if (copysign(1., val) == 1.)
+ strcpy(buf, "inf");
+ else
+ strcpy(buf, "-inf");
+ t = Py_DTST_INFINITE;
+ } else {
+ t = Py_DTST_FINITE;
+ if (flags & Py_DTSF_ADD_DOT_0)
+ format_code = 'Z';
+
+ PyOS_snprintf(format, sizeof(format), "%%%s.%i%c",
+ (flags & Py_DTSF_ALT ? "#" : ""), precision,
+ format_code);
+ _PyOS_ascii_formatd(buf, bufsize, format, val, precision);
+ }
+
+ /* Add sign when requested. It's convenient (esp. when formatting
+ complex numbers) to include a sign even for inf and nan. */
+ if (flags & Py_DTSF_SIGN && buf[0] != '-') {
+ size_t len = strlen(buf);
+ /* the bufsize calculations above should ensure that we've got
+ space to add a sign */
+ assert((size_t)bufsize >= len+2);
+ memmove(buf+1, buf, len+1);
+ buf[0] = '+';
+ }
+ if (upper) {
+ /* Convert to upper case. */
+ char *p1;
+ for (p1 = buf; *p1; p1++)
+ *p1 = Py_TOUPPER(*p1);
+ }
+
+ if (type)
+ *type = t;
+ return buf;
+}
+
+#else
+
+/* _Py_dg_dtoa is available. */
+
+/* I'm using a lookup table here so that I don't have to invent a non-locale
+ specific way to convert to uppercase */
+#define OFS_INF 0
+#define OFS_NAN 1
+#define OFS_E 2
+
+/* The lengths of these are known to the code below, so don't change them */
+static char *lc_float_strings[] = {
+ "inf",
+ "nan",
+ "e",
+};
+static char *uc_float_strings[] = {
+ "INF",
+ "NAN",
+ "E",
+};
+
+
+/* Convert a double d to a string, and return a PyMem_Malloc'd block of
+ memory contain the resulting string.
+
+ Arguments:
+ d is the double to be converted
+ format_code is one of 'e', 'f', 'g', 'r'. 'e', 'f' and 'g'
+ correspond to '%e', '%f' and '%g'; 'r' corresponds to repr.
+ mode is one of '0', '2' or '3', and is completely determined by
+ format_code: 'e' and 'g' use mode 2; 'f' mode 3, 'r' mode 0.
+ precision is the desired precision
+ always_add_sign is nonzero if a '+' sign should be included for positive
+ numbers
+ add_dot_0_if_integer is nonzero if integers in non-exponential form
+ should have ".0" added. Only applies to format codes 'r' and 'g'.
+ use_alt_formatting is nonzero if alternative formatting should be
+ used. Only applies to format codes 'e', 'f' and 'g'. For code 'g',
+ at most one of use_alt_formatting and add_dot_0_if_integer should
+ be nonzero.
+ type, if non-NULL, will be set to one of these constants to identify
+ the type of the 'd' argument:
+ Py_DTST_FINITE
+ Py_DTST_INFINITE
+ Py_DTST_NAN
+
+ Returns a PyMem_Malloc'd block of memory containing the resulting string,
+ or NULL on error. If NULL is returned, the Python error has been set.
+ */
+
+static char *
+format_float_short(double d, char format_code,
+ int mode, Py_ssize_t precision,
+ int always_add_sign, int add_dot_0_if_integer,
+ int use_alt_formatting, char **float_strings, int *type)
+{
+ char *buf = NULL;
+ char *p = NULL;
+ Py_ssize_t bufsize = 0;
+ char *digits, *digits_end;
+ int decpt_as_int, sign, exp_len, exp = 0, use_exp = 0;
+ Py_ssize_t decpt, digits_len, vdigits_start, vdigits_end;
+ _Py_SET_53BIT_PRECISION_HEADER;
+
+ /* _Py_dg_dtoa returns a digit string (no decimal point or exponent).
+ Must be matched by a call to _Py_dg_freedtoa. */
+ _Py_SET_53BIT_PRECISION_START;
+ digits = _Py_dg_dtoa(d, mode, precision, &decpt_as_int, &sign,
+ &digits_end);
+ _Py_SET_53BIT_PRECISION_END;
+
+ decpt = (Py_ssize_t)decpt_as_int;
+ if (digits == NULL) {
+ /* The only failure mode is no memory. */
+ PyErr_NoMemory();
+ goto exit;
+ }
+ assert(digits_end != NULL && digits_end >= digits);
+ digits_len = digits_end - digits;
+
+ if (digits_len && !Py_ISDIGIT(digits[0])) {
+ /* Infinities and nans here; adapt Gay's output,
+ so convert Infinity to inf and NaN to nan, and
+ ignore sign of nan. Then return. */
+
+ /* ignore the actual sign of a nan */
+ if (digits[0] == 'n' || digits[0] == 'N')
+ sign = 0;
+
+ /* We only need 5 bytes to hold the result "+inf\0" . */
+ bufsize = 5; /* Used later in an assert. */
+ buf = (char *)PyMem_Malloc(bufsize);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ p = buf;
+
+ if (sign == 1) {
+ *p++ = '-';
+ }
+ else if (always_add_sign) {
+ *p++ = '+';
+ }
+ if (digits[0] == 'i' || digits[0] == 'I') {
+ strncpy(p, float_strings[OFS_INF], 3);
+ p += 3;
+
+ if (type)
+ *type = Py_DTST_INFINITE;
+ }
+ else if (digits[0] == 'n' || digits[0] == 'N') {
+ strncpy(p, float_strings[OFS_NAN], 3);
+ p += 3;
+
+ if (type)
+ *type = Py_DTST_NAN;
+ }
+ else {
+ /* shouldn't get here: Gay's code should always return
+ something starting with a digit, an 'I', or 'N' */
+ assert(0);
+ }
+ goto exit;
+ }
+
+ /* The result must be finite (not inf or nan). */
+ if (type)
+ *type = Py_DTST_FINITE;
+
+
+ /* We got digits back, format them. We may need to pad 'digits'
+ either on the left or right (or both) with extra zeros, so in
+ general the resulting string has the form
+
+ [<sign>]<zeros><digits><zeros>[<exponent>]
+
+ where either of the <zeros> pieces could be empty, and there's a
+ decimal point that could appear either in <digits> or in the
+ leading or trailing <zeros>.
+
+ Imagine an infinite 'virtual' string vdigits, consisting of the
+ string 'digits' (starting at index 0) padded on both the left and
+ right with infinite strings of zeros. We want to output a slice
+
+ vdigits[vdigits_start : vdigits_end]
+
+ of this virtual string. Thus if vdigits_start < 0 then we'll end
+ up producing some leading zeros; if vdigits_end > digits_len there
+ will be trailing zeros in the output. The next section of code
+ determines whether to use an exponent or not, figures out the
+ position 'decpt' of the decimal point, and computes 'vdigits_start'
+ and 'vdigits_end'. */
+ vdigits_end = digits_len;
+ switch (format_code) {
+ case 'e':
+ use_exp = 1;
+ vdigits_end = precision;
+ break;
+ case 'f':
+ vdigits_end = decpt + precision;
+ break;
+ case 'g':
+ if (decpt <= -4 || decpt >
+ (add_dot_0_if_integer ? precision-1 : precision))
+ use_exp = 1;
+ if (use_alt_formatting)
+ vdigits_end = precision;
+ break;
+ case 'r':
+ /* convert to exponential format at 1e16. We used to convert
+ at 1e17, but that gives odd-looking results for some values
+ when a 16-digit 'shortest' repr is padded with bogus zeros.
+ For example, repr(2e16+8) would give 20000000000000010.0;
+ the true value is 20000000000000008.0. */
+ if (decpt <= -4 || decpt > 16)
+ use_exp = 1;
+ break;
+ default:
+ PyErr_BadInternalCall();
+ goto exit;
+ }
+
+ /* if using an exponent, reset decimal point position to 1 and adjust
+ exponent accordingly.*/
+ if (use_exp) {
+ exp = decpt - 1;
+ decpt = 1;
+ }
+ /* ensure vdigits_start < decpt <= vdigits_end, or vdigits_start <
+ decpt < vdigits_end if add_dot_0_if_integer and no exponent */
+ vdigits_start = decpt <= 0 ? decpt-1 : 0;
+ if (!use_exp && add_dot_0_if_integer)
+ vdigits_end = vdigits_end > decpt ? vdigits_end : decpt + 1;
+ else
+ vdigits_end = vdigits_end > decpt ? vdigits_end : decpt;
+
+ /* double check inequalities */
+ assert(vdigits_start <= 0 &&
+ 0 <= digits_len &&
+ digits_len <= vdigits_end);
+ /* decimal point should be in (vdigits_start, vdigits_end] */
+ assert(vdigits_start < decpt && decpt <= vdigits_end);
+
+ /* Compute an upper bound how much memory we need. This might be a few
+ chars too long, but no big deal. */
+ bufsize =
+ /* sign, decimal point and trailing 0 byte */
+ 3 +
+
+ /* total digit count (including zero padding on both sides) */
+ (vdigits_end - vdigits_start) +
+
+ /* exponent "e+100", max 3 numerical digits */
+ (use_exp ? 5 : 0);
+
+ /* Now allocate the memory and initialize p to point to the start of
+ it. */
+ buf = (char *)PyMem_Malloc(bufsize);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ p = buf;
+
+ /* Add a negative sign if negative, and a plus sign if non-negative
+ and always_add_sign is true. */
+ if (sign == 1)
+ *p++ = '-';
+ else if (always_add_sign)
+ *p++ = '+';
+
+ /* note that exactly one of the three 'if' conditions is true,
+ so we include exactly one decimal point */
+ /* Zero padding on left of digit string */
+ if (decpt <= 0) {
+ memset(p, '0', decpt-vdigits_start);
+ p += decpt - vdigits_start;
+ *p++ = '.';
+ memset(p, '0', 0-decpt);
+ p += 0-decpt;
+ }
+ else {
+ memset(p, '0', 0-vdigits_start);
+ p += 0 - vdigits_start;
+ }
+
+ /* Digits, with included decimal point */
+ if (0 < decpt && decpt <= digits_len) {
+ strncpy(p, digits, decpt-0);
+ p += decpt-0;
+ *p++ = '.';
+ strncpy(p, digits+decpt, digits_len-decpt);
+ p += digits_len-decpt;
+ }
+ else {
+ strncpy(p, digits, digits_len);
+ p += digits_len;
+ }
+
+ /* And zeros on the right */
+ if (digits_len < decpt) {
+ memset(p, '0', decpt-digits_len);
+ p += decpt-digits_len;
+ *p++ = '.';
+ memset(p, '0', vdigits_end-decpt);
+ p += vdigits_end-decpt;
+ }
+ else {
+ memset(p, '0', vdigits_end-digits_len);
+ p += vdigits_end-digits_len;
+ }
+
+ /* Delete a trailing decimal pt unless using alternative formatting. */
+ if (p[-1] == '.' && !use_alt_formatting)
+ p--;
+
+ /* Now that we've done zero padding, add an exponent if needed. */
+ if (use_exp) {
+ *p++ = float_strings[OFS_E][0];
+ exp_len = sprintf(p, "%+.02d", exp);
+ p += exp_len;
+ }
+ exit:
+ if (buf) {
+ *p = '\0';
+ /* It's too late if this fails, as we've already stepped on
+ memory that isn't ours. But it's an okay debugging test. */
+ assert(p-buf < bufsize);
+ }
+ if (digits)
+ _Py_dg_freedtoa(digits);
+
+ return buf;
+}
+
+
+PyAPI_FUNC(char *) PyOS_double_to_string(double val,
+ char format_code,
+ int precision,
+ int flags,
+ int *type)
+{
+ char **float_strings = lc_float_strings;
+ int mode;
+
+ /* Validate format_code, and map upper and lower case. Compute the
+ mode and make any adjustments as needed. */
+ switch (format_code) {
+ /* exponent */
+ case 'E':
+ float_strings = uc_float_strings;
+ format_code = 'e';
+ /* Fall through. */
+ case 'e':
+ mode = 2;
+ precision++;
+ break;
+
+ /* fixed */
+ case 'F':
+ float_strings = uc_float_strings;
+ format_code = 'f';
+ /* Fall through. */
+ case 'f':
+ mode = 3;
+ break;
+
+ /* general */
+ case 'G':
+ float_strings = uc_float_strings;
+ format_code = 'g';
+ /* Fall through. */
+ case 'g':
+ mode = 2;
+ /* precision 0 makes no sense for 'g' format; interpret as 1 */
+ if (precision == 0)
+ precision = 1;
+ break;
+
+ /* repr format */
+ case 'r':
+ mode = 0;
+ /* Supplied precision is unused, must be 0. */
+ if (precision != 0) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ break;
+
+ default:
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ return format_float_short(val, format_code, mode, precision,
+ flags & Py_DTSF_SIGN,
+ flags & Py_DTSF_ADD_DOT_0,
+ flags & Py_DTSF_ALT,
+ float_strings, type);
+}
+#endif /* ifdef PY_NO_SHORT_FLOAT_REPR */
diff --git a/contrib/tools/python/src/Python/pythonrun.c b/contrib/tools/python/src/Python/pythonrun.c
new file mode 100644
index 0000000000..44574d795a
--- /dev/null
+++ b/contrib/tools/python/src/Python/pythonrun.c
@@ -0,0 +1,2088 @@
+
+/* Python interpreter top-level routines, including init/exit */
+
+#include "Python.h"
+
+#include "Python-ast.h"
+#undef Yield /* undefine macro conflicting with winbase.h */
+#include "grammar.h"
+#include "node.h"
+#include "token.h"
+#include "parsetok.h"
+#include "errcode.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "eval.h"
+#include "marshal.h"
+#include "abstract.h"
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef MS_WINDOWS
+#include "malloc.h" /* for alloca */
+#endif
+
+#ifdef HAVE_LANGINFO_H
+#include <locale.h>
+#include <langinfo.h>
+#endif
+
+#ifdef MS_WINDOWS
+#undef BYTE
+#include "windows.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *Py_GetPath(void);
+
+extern grammar _PyParser_Grammar; /* From graminit.c */
+
+/* Forward */
+static void initmain(void);
+static void initsite(void);
+static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *,
+ PyCompilerFlags *, PyArena *);
+static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *,
+ PyCompilerFlags *);
+static void err_input(perrdetail *);
+static void initsigs(void);
+static void wait_for_thread_shutdown(void);
+static void call_sys_exitfunc(void);
+static void call_ll_exitfuncs(void);
+extern void _PyUnicode_Init(void);
+extern void _PyUnicode_Fini(void);
+
+#ifdef WITH_THREAD
+extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
+extern void _PyGILState_Fini(void);
+#endif /* WITH_THREAD */
+
+int Py_DebugFlag; /* Needed by parser.c */
+int Py_VerboseFlag; /* Needed by import.c */
+int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */
+int Py_InspectFlag; /* Needed to determine whether to exit at SystemExit */
+int Py_NoSiteFlag; /* Suppress 'import site' */
+int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */
+int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */
+int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */
+int Py_FrozenFlag = 1; /* Needed by getpath.c */
+int Py_UnicodeFlag = 0; /* Needed by compile.c */
+int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
+/* _XXX Py_QnewFlag should go away in 2.3. It's true iff -Qnew is passed,
+ on the command line, and is used in 2.2 by ceval.c to make all "/" divisions
+ true divisions (which they will be in 2.3). */
+int _Py_QnewFlag = 0;
+int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
+int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */
+
+
+/* Hack to force loading of object files */
+int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \
+ PyOS_mystrnicmp; /* Python/pystrcmp.o */
+
+/* PyModule_GetWarningsModule is no longer necessary as of 2.6
+since _warnings is builtin. This API should not be used. */
+PyObject *
+PyModule_GetWarningsModule(void)
+{
+ return PyImport_ImportModule("warnings");
+}
+
+static void
+_PyDebug_PrintTotalRefs(void)
+{
+#ifdef Py_REF_DEBUG
+ Py_ssize_t total;
+
+ if (!Py_GETENV("PYTHONSHOWREFCOUNT")) {
+ return;
+ }
+
+ total = _Py_GetRefTotal();
+ fprintf(stderr, "[%" PY_FORMAT_SIZE_T "d refs]\n", total);
+#endif
+}
+
+static int initialized = 0;
+
+/* API to access the initialized flag -- useful for esoteric use */
+
+int
+Py_IsInitialized(void)
+{
+ return initialized;
+}
+
+/* Global initializations. Can be undone by Py_Finalize(). Don't
+ call this twice without an intervening Py_Finalize() call. When
+ initializations fail, a fatal error is issued and the function does
+ not return. On return, the first thread and interpreter state have
+ been created.
+
+ Locking: you must hold the interpreter lock while calling this.
+ (If the lock has not yet been initialized, that's equivalent to
+ having the lock, but you cannot use multiple threads.)
+
+*/
+
+static int
+add_flag(int flag, const char *envs)
+{
+ int env = atoi(envs);
+ if (flag < env)
+ flag = env;
+ if (flag < 1)
+ flag = 1;
+ return flag;
+}
+
+static int
+isatty_no_error(PyObject *sys_stream)
+{
+ PyObject *sys_isatty = PyObject_CallMethod(sys_stream, "isatty", "");
+ if (sys_isatty) {
+ int isatty = PyObject_IsTrue(sys_isatty);
+ Py_DECREF(sys_isatty);
+ if (isatty >= 0)
+ return isatty;
+ }
+ PyErr_Clear();
+ return 0;
+}
+
+static void
+inittracemalloc(void)
+{
+ PyObject *mod = NULL, *res = NULL;
+ char *p, *endptr;
+ long nframe;
+
+ p = Py_GETENV("PYTHONTRACEMALLOC");
+ if (p == NULL || *p == '\0')
+ return;
+
+ endptr = p;
+ nframe = strtol(p, &endptr, 10);
+ if (*endptr != '\0' || nframe < 1 || nframe > 100000)
+ Py_FatalError("PYTHONTRACEMALLOC: invalid number of frames");
+
+ mod = PyImport_ImportModule("_tracemalloc");
+ if (mod == NULL)
+ goto error;
+
+ res = PyObject_CallMethod(mod, "start", "i", (int)nframe);
+ if (res == NULL)
+ goto error;
+
+ goto done;
+
+error:
+ fprintf(stderr, "failed to start tracemalloc:\n");
+ PyErr_Print();
+
+done:
+ Py_XDECREF(mod);
+ Py_XDECREF(res);
+}
+
+
+void
+Py_InitializeEx(int install_sigs)
+{
+ char *p_ignore;
+ if ((p_ignore = getenv("PY_IGNORE_ENVIRONMENT")) && *p_ignore == 'x') {
+ Py_IgnoreEnvironmentFlag = 1;
+ }
+ PyInterpreterState *interp;
+ PyThreadState *tstate;
+ PyObject *bimod, *sysmod;
+ char *p;
+ char *icodeset = NULL; /* On Windows, input codeset may theoretically
+ differ from output codeset. */
+ char *codeset = NULL;
+ char *errors = NULL;
+ int free_codeset = 0;
+ int overridden = 0;
+ PyObject *sys_stream;
+#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
+ char *saved_locale, *loc_codeset;
+#endif
+#ifdef MS_WINDOWS
+ char ibuf[128];
+ char buf[128];
+#endif
+ extern void _Py_ReadyTypes(void);
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+ if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0')
+ Py_DebugFlag = add_flag(Py_DebugFlag, p);
+ if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0')
+ Py_VerboseFlag = add_flag(Py_VerboseFlag, p);
+ if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0')
+ Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p);
+ if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0')
+ Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p);
+ /* The variable is only tested for existence here; _PyRandom_Init will
+ check its value further. */
+ if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0')
+ Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p);
+
+ _PyRandom_Init();
+
+ interp = PyInterpreterState_New();
+ if (interp == NULL)
+ Py_FatalError("Py_Initialize: can't make first interpreter");
+
+ tstate = PyThreadState_New(interp);
+ if (tstate == NULL)
+ Py_FatalError("Py_Initialize: can't make first thread");
+ (void) PyThreadState_Swap(tstate);
+
+ _Py_ReadyTypes();
+
+ if (!_PyFrame_Init())
+ Py_FatalError("Py_Initialize: can't init frames");
+
+ if (!_PyInt_Init())
+ Py_FatalError("Py_Initialize: can't init ints");
+
+ if (!_PyLong_Init())
+ Py_FatalError("Py_Initialize: can't init longs");
+
+ if (!PyByteArray_Init())
+ Py_FatalError("Py_Initialize: can't init bytearray");
+
+ _PyFloat_Init();
+
+ interp->modules = PyDict_New();
+ if (interp->modules == NULL)
+ Py_FatalError("Py_Initialize: can't make modules dictionary");
+ interp->modules_reloading = PyDict_New();
+ if (interp->modules_reloading == NULL)
+ Py_FatalError("Py_Initialize: can't make modules_reloading dictionary");
+
+#ifdef Py_USING_UNICODE
+ /* Init Unicode implementation; relies on the codec registry */
+ _PyUnicode_Init();
+#endif
+
+ bimod = _PyBuiltin_Init();
+ if (bimod == NULL)
+ Py_FatalError("Py_Initialize: can't initialize __builtin__");
+ interp->builtins = PyModule_GetDict(bimod);
+ if (interp->builtins == NULL)
+ Py_FatalError("Py_Initialize: can't initialize builtins dict");
+ Py_INCREF(interp->builtins);
+
+ sysmod = _PySys_Init();
+ if (sysmod == NULL)
+ Py_FatalError("Py_Initialize: can't initialize sys");
+ interp->sysdict = PyModule_GetDict(sysmod);
+ if (interp->sysdict == NULL)
+ Py_FatalError("Py_Initialize: can't initialize sys dict");
+ Py_INCREF(interp->sysdict);
+ _PyImport_FixupExtension("sys", "sys");
+ PySys_SetPath(Py_GetPath());
+ PyDict_SetItemString(interp->sysdict, "modules",
+ interp->modules);
+
+ _PyImport_Init();
+
+ /* initialize builtin exceptions */
+ _PyExc_Init();
+ _PyImport_FixupExtension("exceptions", "exceptions");
+
+ /* phase 2 of builtins */
+ _PyImport_FixupExtension("__builtin__", "__builtin__");
+
+ _PyImportHooks_Init();
+
+ if (install_sigs)
+ initsigs(); /* Signal handling stuff, including initintr() */
+
+ /* Initialize warnings. */
+ _PyWarnings_Init();
+ if (PySys_HasWarnOptions()) {
+ PyObject *warnings_module = PyImport_ImportModule("warnings");
+ if (!warnings_module)
+ PyErr_Clear();
+ Py_XDECREF(warnings_module);
+ }
+
+ initmain(); /* Module __main__ */
+
+ /* auto-thread-state API, if available */
+#ifdef WITH_THREAD
+ _PyGILState_Init(interp, tstate);
+#endif /* WITH_THREAD */
+
+ if (!Py_NoSiteFlag)
+ initsite(); /* Module site */
+
+ inittracemalloc();
+
+ if ((p = Py_GETENV("PYTHONIOENCODING")) && *p != '\0') {
+ p = icodeset = codeset = strdup(p);
+ free_codeset = 1;
+ errors = strchr(p, ':');
+ if (errors) {
+ *errors = '\0';
+ errors++;
+ }
+ overridden = 1;
+ }
+
+#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
+ /* On Unix, set the file system encoding according to the
+ user's preference, if the CODESET names a well-known
+ Python codec, and Py_FileSystemDefaultEncoding isn't
+ initialized by other means. Also set the encoding of
+ stdin and stdout if these are terminals, unless overridden. */
+
+ if (!overridden || !Py_FileSystemDefaultEncoding) {
+ saved_locale = strdup(setlocale(LC_CTYPE, NULL));
+ setlocale(LC_CTYPE, "");
+ loc_codeset = nl_langinfo(CODESET);
+ if (loc_codeset && *loc_codeset) {
+ PyObject *enc = PyCodec_Encoder(loc_codeset);
+ if (enc) {
+ loc_codeset = strdup(loc_codeset);
+ Py_DECREF(enc);
+ } else {
+ if (PyErr_ExceptionMatches(PyExc_LookupError)) {
+ PyErr_Clear();
+ loc_codeset = NULL;
+ } else {
+ PyErr_Print();
+ exit(1);
+ }
+ }
+ } else
+ loc_codeset = NULL;
+ setlocale(LC_CTYPE, saved_locale);
+ free(saved_locale);
+
+ if (!overridden) {
+ codeset = icodeset = loc_codeset;
+ free_codeset = 1;
+ }
+
+ /* Initialize Py_FileSystemDefaultEncoding from
+ locale even if PYTHONIOENCODING is set. */
+ if (!Py_FileSystemDefaultEncoding) {
+ Py_FileSystemDefaultEncoding = loc_codeset;
+ if (!overridden)
+ free_codeset = 0;
+ }
+ }
+#endif
+
+#ifdef MS_WINDOWS
+ if (!overridden) {
+ icodeset = ibuf;
+ codeset = buf;
+ sprintf(ibuf, "cp%d", GetConsoleCP());
+ sprintf(buf, "cp%d", GetConsoleOutputCP());
+ }
+#endif
+
+ if (codeset) {
+ sys_stream = PySys_GetObject("stdin");
+ if ((overridden || isatty_no_error(sys_stream)) &&
+ PyFile_Check(sys_stream)) {
+ if (!PyFile_SetEncodingAndErrors(sys_stream, icodeset, errors))
+ Py_FatalError("Cannot set codeset of stdin");
+ }
+
+ sys_stream = PySys_GetObject("stdout");
+ if ((overridden || isatty_no_error(sys_stream)) &&
+ PyFile_Check(sys_stream)) {
+ if (!PyFile_SetEncodingAndErrors(sys_stream, codeset, errors))
+ Py_FatalError("Cannot set codeset of stdout");
+ }
+
+ sys_stream = PySys_GetObject("stderr");
+ if ((overridden || isatty_no_error(sys_stream)) &&
+ PyFile_Check(sys_stream)) {
+ if (!PyFile_SetEncodingAndErrors(sys_stream, codeset, errors))
+ Py_FatalError("Cannot set codeset of stderr");
+ }
+
+ if (free_codeset)
+ free(codeset);
+ }
+}
+
+void
+Py_Initialize(void)
+{
+ Py_InitializeEx(1);
+}
+
+
+#ifdef COUNT_ALLOCS
+extern void dump_counts(FILE*);
+#endif
+
+/* Undo the effect of Py_Initialize().
+
+ Beware: if multiple interpreter and/or thread states exist, these
+ are not wiped out; only the current thread and interpreter state
+ are deleted. But since everything else is deleted, those other
+ interpreter and thread states should no longer be used.
+
+ (XXX We should do better, e.g. wipe out all interpreters and
+ threads.)
+
+ Locking: as above.
+
+*/
+
+void
+Py_Finalize(void)
+{
+ PyInterpreterState *interp;
+ PyThreadState *tstate;
+
+ if (!initialized)
+ return;
+
+ wait_for_thread_shutdown();
+
+ /* The interpreter is still entirely intact at this point, and the
+ * exit funcs may be relying on that. In particular, if some thread
+ * or exit func is still waiting to do an import, the import machinery
+ * expects Py_IsInitialized() to return true. So don't say the
+ * interpreter is uninitialized until after the exit funcs have run.
+ * Note that Threading.py uses an exit func to do a join on all the
+ * threads created thru it, so this also protects pending imports in
+ * the threads created via Threading.
+ */
+ call_sys_exitfunc();
+ initialized = 0;
+
+ /* Get current thread state and interpreter pointer */
+ tstate = PyThreadState_GET();
+ interp = tstate->interp;
+
+ /* Disable signal handling */
+ PyOS_FiniInterrupts();
+
+ /* Clear type lookup cache */
+ PyType_ClearCache();
+
+ /* Collect garbage. This may call finalizers; it's nice to call these
+ * before all modules are destroyed.
+ * XXX If a __del__ or weakref callback is triggered here, and tries to
+ * XXX import a module, bad things can happen, because Python no
+ * XXX longer believes it's initialized.
+ * XXX Fatal Python error: Interpreter not initialized (version mismatch?)
+ * XXX is easy to provoke that way. I've also seen, e.g.,
+ * XXX Exception exceptions.ImportError: 'No module named sha'
+ * XXX in <function callback at 0x008F5718> ignored
+ * XXX but I'm unclear on exactly how that one happens. In any case,
+ * XXX I haven't seen a real-life report of either of these.
+ */
+ PyGC_Collect();
+#ifdef COUNT_ALLOCS
+ /* With COUNT_ALLOCS, it helps to run GC multiple times:
+ each collection might release some types from the type
+ list, so they become garbage. */
+ while (PyGC_Collect() > 0)
+ /* nothing */;
+#endif
+
+ /* Destroy all modules */
+ PyImport_Cleanup();
+
+ /* Collect final garbage. This disposes of cycles created by
+ * new-style class definitions, for example.
+ * XXX This is disabled because it caused too many problems. If
+ * XXX a __del__ or weakref callback triggers here, Python code has
+ * XXX a hard time running, because even the sys module has been
+ * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc).
+ * XXX One symptom is a sequence of information-free messages
+ * XXX coming from threads (if a __del__ or callback is invoked,
+ * XXX other threads can execute too, and any exception they encounter
+ * XXX triggers a comedy of errors as subsystem after subsystem
+ * XXX fails to find what it *expects* to find in sys to help report
+ * XXX the exception and consequent unexpected failures). I've also
+ * XXX seen segfaults then, after adding print statements to the
+ * XXX Python code getting called.
+ */
+#if 0
+ PyGC_Collect();
+#endif
+
+ /* Destroy the database used by _PyImport_{Fixup,Find}Extension */
+ _PyImport_Fini();
+
+ /* Debugging stuff */
+#ifdef COUNT_ALLOCS
+ if (Py_GETENV("PYTHONSHOWALLOCCOUNT")) {
+ dump_counts(stderr);
+ }
+#endif
+
+ _PyDebug_PrintTotalRefs();
+
+#ifdef Py_TRACE_REFS
+ /* Display all objects still alive -- this can invoke arbitrary
+ * __repr__ overrides, so requires a mostly-intact interpreter.
+ * Alas, a lot of stuff may still be alive now that will be cleaned
+ * up later.
+ */
+ if (Py_GETENV("PYTHONDUMPREFS"))
+ _Py_PrintReferences(stderr);
+#endif /* Py_TRACE_REFS */
+
+ /* Clear interpreter state */
+ PyInterpreterState_Clear(interp);
+
+ /* Now we decref the exception classes. After this point nothing
+ can raise an exception. That's okay, because each Fini() method
+ below has been checked to make sure no exceptions are ever
+ raised.
+ */
+
+ _PyExc_Fini();
+
+ /* Cleanup auto-thread-state */
+#ifdef WITH_THREAD
+ _PyGILState_Fini();
+#endif /* WITH_THREAD */
+
+ /* Delete current thread */
+ PyThreadState_Swap(NULL);
+ PyInterpreterState_Delete(interp);
+
+ /* Sundry finalizers */
+ PyMethod_Fini();
+ PyFrame_Fini();
+ PyCFunction_Fini();
+ PyTuple_Fini();
+ PyList_Fini();
+ PySet_Fini();
+ PyString_Fini();
+ PyByteArray_Fini();
+ PyInt_Fini();
+ PyFloat_Fini();
+ PyDict_Fini();
+ _PyRandom_Fini();
+
+#ifdef Py_USING_UNICODE
+ /* Cleanup Unicode implementation */
+ _PyUnicode_Fini();
+#endif
+
+ /* XXX Still allocated:
+ - various static ad-hoc pointers to interned strings
+ - int and float free list blocks
+ - whatever various modules and libraries allocate
+ */
+
+ PyGrammar_RemoveAccelerators(&_PyParser_Grammar);
+
+#ifdef Py_TRACE_REFS
+ /* Display addresses (& refcnts) of all objects still alive.
+ * An address can be used to find the repr of the object, printed
+ * above by _Py_PrintReferences.
+ */
+ if (Py_GETENV("PYTHONDUMPREFS"))
+ _Py_PrintReferenceAddresses(stderr);
+#endif /* Py_TRACE_REFS */
+#ifdef PYMALLOC_DEBUG
+ if (Py_GETENV("PYTHONMALLOCSTATS"))
+ _PyObject_DebugMallocStats();
+#endif
+
+ call_ll_exitfuncs();
+}
+
+/* Create and initialize a new interpreter and thread, and return the
+ new thread. This requires that Py_Initialize() has been called
+ first.
+
+ Unsuccessful initialization yields a NULL pointer. Note that *no*
+ exception information is available even in this case -- the
+ exception information is held in the thread, and there is no
+ thread.
+
+ Locking: as above.
+
+*/
+
+PyThreadState *
+Py_NewInterpreter(void)
+{
+ PyInterpreterState *interp;
+ PyThreadState *tstate, *save_tstate;
+ PyObject *bimod, *sysmod;
+
+ if (!initialized)
+ Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
+
+ interp = PyInterpreterState_New();
+ if (interp == NULL)
+ return NULL;
+
+ tstate = PyThreadState_New(interp);
+ if (tstate == NULL) {
+ PyInterpreterState_Delete(interp);
+ return NULL;
+ }
+
+ save_tstate = PyThreadState_Swap(tstate);
+
+ /* XXX The following is lax in error checking */
+
+ interp->modules = PyDict_New();
+ interp->modules_reloading = PyDict_New();
+
+ bimod = _PyImport_FindExtension("__builtin__", "__builtin__");
+ if (bimod != NULL) {
+ interp->builtins = PyModule_GetDict(bimod);
+ if (interp->builtins == NULL)
+ goto handle_error;
+ Py_INCREF(interp->builtins);
+ }
+ sysmod = _PyImport_FindExtension("sys", "sys");
+ if (bimod != NULL && sysmod != NULL) {
+ interp->sysdict = PyModule_GetDict(sysmod);
+ if (interp->sysdict == NULL)
+ goto handle_error;
+ Py_INCREF(interp->sysdict);
+ PySys_SetPath(Py_GetPath());
+ PyDict_SetItemString(interp->sysdict, "modules",
+ interp->modules);
+ _PyImportHooks_Init();
+ initmain();
+ if (!Py_NoSiteFlag)
+ initsite();
+ }
+
+ if (!PyErr_Occurred())
+ return tstate;
+
+handle_error:
+ /* Oops, it didn't work. Undo it all. */
+
+ PyErr_Print();
+ PyThreadState_Clear(tstate);
+ PyThreadState_Swap(save_tstate);
+ PyThreadState_Delete(tstate);
+ PyInterpreterState_Delete(interp);
+
+ return NULL;
+}
+
+/* Delete an interpreter and its last thread. This requires that the
+ given thread state is current, that the thread has no remaining
+ frames, and that it is its interpreter's only remaining thread.
+ It is a fatal error to violate these constraints.
+
+ (Py_Finalize() doesn't have these constraints -- it zaps
+ everything, regardless.)
+
+ Locking: as above.
+
+*/
+
+void
+Py_EndInterpreter(PyThreadState *tstate)
+{
+ PyInterpreterState *interp = tstate->interp;
+
+ if (tstate != PyThreadState_GET())
+ Py_FatalError("Py_EndInterpreter: thread is not current");
+ if (tstate->frame != NULL)
+ Py_FatalError("Py_EndInterpreter: thread still has a frame");
+ if (tstate != interp->tstate_head || tstate->next != NULL)
+ Py_FatalError("Py_EndInterpreter: not the last thread");
+
+ PyImport_Cleanup();
+ PyInterpreterState_Clear(interp);
+ PyThreadState_Swap(NULL);
+ PyInterpreterState_Delete(interp);
+}
+
+static char *progname = "python";
+
+void
+Py_SetProgramName(const char *pn)
+{
+ if (pn && *pn)
+ progname = pn;
+}
+
+char *
+Py_GetProgramName(void)
+{
+ return progname;
+}
+
+static char *default_home = NULL;
+
+void
+Py_SetPythonHome(char *home)
+{
+ default_home = home;
+}
+
+char *
+Py_GetPythonHome(void)
+{
+ char *home = default_home;
+ if (home == NULL && !Py_IgnoreEnvironmentFlag)
+ home = Py_GETENV("PYTHONHOME");
+ return home;
+}
+
+/* Create __main__ module */
+
+static void
+initmain(void)
+{
+ PyObject *m, *d;
+ m = PyImport_AddModule("__main__");
+ if (m == NULL)
+ Py_FatalError("can't create __main__ module");
+ d = PyModule_GetDict(m);
+ if (PyDict_GetItemString(d, "__builtins__") == NULL) {
+ PyObject *bimod = PyImport_ImportModule("__builtin__");
+ if (bimod == NULL ||
+ PyDict_SetItemString(d, "__builtins__", bimod) != 0)
+ Py_FatalError("can't add __builtins__ to __main__");
+ Py_XDECREF(bimod);
+ }
+}
+
+/* Import the site module (not into __main__ though) */
+
+static void
+initsite(void)
+{
+ PyObject *m;
+ m = PyImport_ImportModule("site");
+ if (m == NULL) {
+ PyErr_Print();
+ Py_Finalize();
+ exit(1);
+ }
+ else {
+ Py_DECREF(m);
+ }
+}
+
+/* Parse input from a file and execute it */
+
+int
+PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
+ PyCompilerFlags *flags)
+{
+ if (filename == NULL)
+ filename = "???";
+ if (Py_FdIsInteractive(fp, filename)) {
+ int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
+ if (closeit)
+ fclose(fp);
+ return err;
+ }
+ else
+ return PyRun_SimpleFileExFlags(fp, filename, closeit, flags);
+}
+
+int
+PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
+{
+ PyObject *v;
+ int ret;
+ PyCompilerFlags local_flags;
+
+ if (flags == NULL) {
+ flags = &local_flags;
+ local_flags.cf_flags = 0;
+ }
+ v = PySys_GetObject("ps1");
+ if (v == NULL) {
+ PySys_SetObject("ps1", v = PyString_FromString(">>> "));
+ Py_XDECREF(v);
+ }
+ v = PySys_GetObject("ps2");
+ if (v == NULL) {
+ PySys_SetObject("ps2", v = PyString_FromString("... "));
+ Py_XDECREF(v);
+ }
+ for (;;) {
+ ret = PyRun_InteractiveOneFlags(fp, filename, flags);
+ _PyDebug_PrintTotalRefs();
+ if (ret == E_EOF)
+ return 0;
+ /*
+ if (ret == E_NOMEM)
+ return -1;
+ */
+ }
+}
+
+#if 0
+/* compute parser flags based on compiler flags */
+#define PARSER_FLAGS(flags) \
+ ((flags) ? ((((flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
+ PyPARSE_DONT_IMPLY_DEDENT : 0)) : 0)
+#endif
+#if 1
+/* Keep an example of flags with future keyword support. */
+#define PARSER_FLAGS(flags) \
+ ((flags) ? ((((flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
+ PyPARSE_DONT_IMPLY_DEDENT : 0) \
+ | (((flags)->cf_flags & CO_FUTURE_PRINT_FUNCTION) ? \
+ PyPARSE_PRINT_IS_FUNCTION : 0) \
+ | (((flags)->cf_flags & CO_FUTURE_UNICODE_LITERALS) ? \
+ PyPARSE_UNICODE_LITERALS : 0) \
+ ) : 0)
+#endif
+
+int
+PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
+{
+ PyObject *m, *d, *v, *w;
+ mod_ty mod;
+ PyArena *arena;
+ char *ps1 = "", *ps2 = "";
+ int errcode = 0;
+
+ v = PySys_GetObject("ps1");
+ if (v != NULL) {
+ v = PyObject_Str(v);
+ if (v == NULL)
+ PyErr_Clear();
+ else if (PyString_Check(v))
+ ps1 = PyString_AsString(v);
+ }
+ w = PySys_GetObject("ps2");
+ if (w != NULL) {
+ w = PyObject_Str(w);
+ if (w == NULL)
+ PyErr_Clear();
+ else if (PyString_Check(w))
+ ps2 = PyString_AsString(w);
+ }
+ arena = PyArena_New();
+ if (arena == NULL) {
+ Py_XDECREF(v);
+ Py_XDECREF(w);
+ return -1;
+ }
+ mod = PyParser_ASTFromFile(fp, filename,
+ Py_single_input, ps1, ps2,
+ flags, &errcode, arena);
+ Py_XDECREF(v);
+ Py_XDECREF(w);
+ if (mod == NULL) {
+ PyArena_Free(arena);
+ if (errcode == E_EOF) {
+ PyErr_Clear();
+ return E_EOF;
+ }
+ PyErr_Print();
+ return -1;
+ }
+ m = PyImport_AddModule("__main__");
+ if (m == NULL) {
+ PyArena_Free(arena);
+ return -1;
+ }
+ d = PyModule_GetDict(m);
+ v = run_mod(mod, filename, d, d, flags, arena);
+ PyArena_Free(arena);
+ if (v == NULL) {
+ PyErr_Print();
+ return -1;
+ }
+ Py_DECREF(v);
+ if (Py_FlushLine())
+ PyErr_Clear();
+ return 0;
+}
+
+/* Check whether a file maybe a pyc file: Look at the extension,
+ the file type, and, if we may close it, at the first few bytes. */
+
+static int
+maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit)
+{
+ if (strcmp(ext, ".pyc") == 0 || strcmp(ext, ".pyo") == 0)
+ return 1;
+
+ /* Only look into the file if we are allowed to close it, since
+ it then should also be seekable. */
+ if (closeit) {
+ /* Read only two bytes of the magic. If the file was opened in
+ text mode, the bytes 3 and 4 of the magic (\r\n) might not
+ be read as they are on disk. */
+ unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF;
+ unsigned char buf[2];
+ /* Mess: In case of -x, the stream is NOT at its start now,
+ and ungetc() was used to push back the first newline,
+ which makes the current stream position formally undefined,
+ and a x-platform nightmare.
+ Unfortunately, we have no direct way to know whether -x
+ was specified. So we use a terrible hack: if the current
+ stream position is not 0, we assume -x was specified, and
+ give up. Bug 132850 on SourceForge spells out the
+ hopelessness of trying anything else (fseek and ftell
+ don't work predictably x-platform for text-mode files).
+ */
+ int ispyc = 0;
+ if (ftell(fp) == 0) {
+ if (fread(buf, 1, 2, fp) == 2 &&
+ ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic)
+ ispyc = 1;
+ rewind(fp);
+ }
+ return ispyc;
+ }
+ return 0;
+}
+
+int
+PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
+ PyCompilerFlags *flags)
+{
+ PyObject *m, *d, *v;
+ const char *ext;
+ int set_file_name = 0, len, ret = -1;
+
+ m = PyImport_AddModule("__main__");
+ if (m == NULL)
+ return -1;
+ Py_INCREF(m);
+ d = PyModule_GetDict(m);
+ if (PyDict_GetItemString(d, "__file__") == NULL) {
+ PyObject *f = PyString_FromString(filename);
+ if (f == NULL)
+ goto done;
+ if (PyDict_SetItemString(d, "__file__", f) < 0) {
+ Py_DECREF(f);
+ goto done;
+ }
+ set_file_name = 1;
+ Py_DECREF(f);
+ }
+ len = strlen(filename);
+ ext = filename + len - (len > 4 ? 4 : 0);
+ if (maybe_pyc_file(fp, filename, ext, closeit)) {
+ /* Try to run a pyc file. First, re-open in binary */
+ if (closeit)
+ fclose(fp);
+ if ((fp = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "python: Can't reopen .pyc file\n");
+ goto done;
+ }
+ /* Turn on optimization if a .pyo file is given */
+ if (strcmp(ext, ".pyo") == 0)
+ Py_OptimizeFlag = 1;
+ v = run_pyc_file(fp, filename, d, d, flags);
+ } else {
+ v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
+ closeit, flags);
+ }
+ if (v == NULL) {
+ PyErr_Print();
+ goto done;
+ }
+ Py_DECREF(v);
+ if (Py_FlushLine())
+ PyErr_Clear();
+ ret = 0;
+ done:
+ if (set_file_name && PyDict_DelItemString(d, "__file__"))
+ PyErr_Clear();
+ Py_DECREF(m);
+ return ret;
+}
+
+int
+PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
+{
+ PyObject *m, *d, *v;
+ m = PyImport_AddModule("__main__");
+ if (m == NULL)
+ return -1;
+ d = PyModule_GetDict(m);
+ v = PyRun_StringFlags(command, Py_file_input, d, d, flags);
+ if (v == NULL) {
+ PyErr_Print();
+ return -1;
+ }
+ Py_DECREF(v);
+ if (Py_FlushLine())
+ PyErr_Clear();
+ return 0;
+}
+
+static int
+parse_syntax_error(PyObject *err, PyObject **message, const char **filename,
+ int *lineno, int *offset, const char **text)
+{
+ long hold;
+ PyObject *v;
+
+ /* old style errors */
+ if (PyTuple_Check(err))
+ return PyArg_ParseTuple(err, "O(ziiz)", message, filename,
+ lineno, offset, text);
+
+ *message = NULL;
+
+ /* new style errors. `err' is an instance */
+ *message = PyObject_GetAttrString(err, "msg");
+ if (!*message)
+ goto finally;
+
+ v = PyObject_GetAttrString(err, "filename");
+ if (!v)
+ goto finally;
+ if (v == Py_None) {
+ Py_DECREF(v);
+ *filename = NULL;
+ }
+ else {
+ *filename = PyString_AsString(v);
+ Py_DECREF(v);
+ if (!*filename)
+ goto finally;
+ }
+
+ v = PyObject_GetAttrString(err, "lineno");
+ if (!v)
+ goto finally;
+ hold = PyInt_AsLong(v);
+ Py_DECREF(v);
+ if (hold < 0 && PyErr_Occurred())
+ goto finally;
+ *lineno = (int)hold;
+
+ v = PyObject_GetAttrString(err, "offset");
+ if (!v)
+ goto finally;
+ if (v == Py_None) {
+ *offset = -1;
+ Py_DECREF(v);
+ } else {
+ hold = PyInt_AsLong(v);
+ Py_DECREF(v);
+ if (hold < 0 && PyErr_Occurred())
+ goto finally;
+ *offset = (int)hold;
+ }
+
+ v = PyObject_GetAttrString(err, "text");
+ if (!v)
+ goto finally;
+ if (v == Py_None) {
+ Py_DECREF(v);
+ *text = NULL;
+ }
+ else {
+ *text = PyString_AsString(v);
+ Py_DECREF(v);
+ if (!*text)
+ goto finally;
+ }
+ return 1;
+
+finally:
+ Py_XDECREF(*message);
+ return 0;
+}
+
+void
+PyErr_Print(void)
+{
+ PyErr_PrintEx(1);
+}
+
+static void
+print_error_text(PyObject *f, int offset, const char *text)
+{
+ char *nl;
+ if (offset >= 0) {
+ if (offset > 0 && offset == strlen(text) && text[offset - 1] == '\n')
+ offset--;
+ for (;;) {
+ nl = strchr(text, '\n');
+ if (nl == NULL || nl-text >= offset)
+ break;
+ offset -= (int)(nl+1-text);
+ text = nl+1;
+ }
+ while (*text == ' ' || *text == '\t') {
+ text++;
+ offset--;
+ }
+ }
+ PyFile_WriteString(" ", f);
+ PyFile_WriteString(text, f);
+ if (*text == '\0' || text[strlen(text)-1] != '\n')
+ PyFile_WriteString("\n", f);
+ if (offset == -1)
+ return;
+ PyFile_WriteString(" ", f);
+ offset--;
+ while (offset > 0) {
+ PyFile_WriteString(" ", f);
+ offset--;
+ }
+ PyFile_WriteString("^\n", f);
+}
+
+static void
+handle_system_exit(void)
+{
+ PyObject *exception, *value, *tb;
+ int exitcode = 0;
+
+ if (Py_InspectFlag)
+ /* Don't exit if -i flag was given. This flag is set to 0
+ * when entering interactive mode for inspecting. */
+ return;
+
+ PyErr_Fetch(&exception, &value, &tb);
+ if (Py_FlushLine())
+ PyErr_Clear();
+ fflush(stdout);
+ if (value == NULL || value == Py_None)
+ goto done;
+ if (PyExceptionInstance_Check(value)) {
+ /* The error code should be in the `code' attribute. */
+ PyObject *code = PyObject_GetAttrString(value, "code");
+ if (code) {
+ Py_DECREF(value);
+ value = code;
+ if (value == Py_None)
+ goto done;
+ }
+ /* If we failed to dig out the 'code' attribute,
+ just let the else clause below print the error. */
+ }
+ if (_PyAnyInt_Check(value))
+ exitcode = (int)PyInt_AsLong(value);
+ else {
+ PyObject *sys_stderr = PySys_GetObject("stderr");
+ if (sys_stderr != NULL && sys_stderr != Py_None) {
+ PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
+ } else {
+ PyObject_Print(value, stderr, Py_PRINT_RAW);
+ fflush(stderr);
+ }
+ PySys_WriteStderr("\n");
+ exitcode = 1;
+ }
+ done:
+ /* Restore and clear the exception info, in order to properly decref
+ * the exception, value, and traceback. If we just exit instead,
+ * these leak, which confuses PYTHONDUMPREFS output, and may prevent
+ * some finalizers from running.
+ */
+ PyErr_Restore(exception, value, tb);
+ PyErr_Clear();
+ Py_Exit(exitcode);
+ /* NOTREACHED */
+}
+
+void
+PyErr_PrintEx(int set_sys_last_vars)
+{
+ PyObject *exception, *v, *tb, *hook;
+
+ if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
+ handle_system_exit();
+ }
+ PyErr_Fetch(&exception, &v, &tb);
+ if (exception == NULL)
+ return;
+ PyErr_NormalizeException(&exception, &v, &tb);
+ if (exception == NULL)
+ return;
+ /* Now we know v != NULL too */
+ if (set_sys_last_vars) {
+ PySys_SetObject("last_type", exception);
+ PySys_SetObject("last_value", v);
+ PySys_SetObject("last_traceback", tb);
+ }
+ hook = PySys_GetObject("excepthook");
+ if (hook && hook != Py_None) {
+ PyObject *args = PyTuple_Pack(3,
+ exception, v, tb ? tb : Py_None);
+ PyObject *result = PyEval_CallObject(hook, args);
+ if (result == NULL) {
+ PyObject *exception2, *v2, *tb2;
+ if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
+ handle_system_exit();
+ }
+ PyErr_Fetch(&exception2, &v2, &tb2);
+ PyErr_NormalizeException(&exception2, &v2, &tb2);
+ /* It should not be possible for exception2 or v2
+ to be NULL. However PyErr_Display() can't
+ tolerate NULLs, so just be safe. */
+ if (exception2 == NULL) {
+ exception2 = Py_None;
+ Py_INCREF(exception2);
+ }
+ if (v2 == NULL) {
+ v2 = Py_None;
+ Py_INCREF(v2);
+ }
+ if (Py_FlushLine())
+ PyErr_Clear();
+ fflush(stdout);
+ PySys_WriteStderr("Error in sys.excepthook:\n");
+ PyErr_Display(exception2, v2, tb2);
+ PySys_WriteStderr("\nOriginal exception was:\n");
+ PyErr_Display(exception, v, tb);
+ Py_DECREF(exception2);
+ Py_DECREF(v2);
+ Py_XDECREF(tb2);
+ }
+ Py_XDECREF(result);
+ Py_XDECREF(args);
+ } else {
+ PySys_WriteStderr("sys.excepthook is missing\n");
+ PyErr_Display(exception, v, tb);
+ }
+ Py_XDECREF(exception);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+}
+
+void
+PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
+{
+ int err = 0;
+ PyObject *f = PySys_GetObject("stderr");
+ Py_INCREF(value);
+ if (f == NULL || f == Py_None)
+ fprintf(stderr, "lost sys.stderr\n");
+ else {
+ if (Py_FlushLine())
+ PyErr_Clear();
+ fflush(stdout);
+ if (tb && tb != Py_None)
+ err = PyTraceBack_Print(tb, f);
+ if (err == 0 &&
+ PyObject_HasAttrString(value, "print_file_and_line"))
+ {
+ PyObject *message;
+ const char *filename, *text;
+ int lineno, offset;
+ if (!parse_syntax_error(value, &message, &filename,
+ &lineno, &offset, &text))
+ PyErr_Clear();
+ else {
+ char buf[10];
+ PyFile_WriteString(" File \"", f);
+ if (filename == NULL)
+ PyFile_WriteString("<string>", f);
+ else
+ PyFile_WriteString(filename, f);
+ PyFile_WriteString("\", line ", f);
+ PyOS_snprintf(buf, sizeof(buf), "%d", lineno);
+ PyFile_WriteString(buf, f);
+ PyFile_WriteString("\n", f);
+ if (text != NULL)
+ print_error_text(f, offset, text);
+ Py_DECREF(value);
+ value = message;
+ /* Can't be bothered to check all those
+ PyFile_WriteString() calls */
+ if (PyErr_Occurred())
+ err = -1;
+ }
+ }
+ if (err) {
+ /* Don't do anything else */
+ }
+ else if (PyExceptionClass_Check(exception)) {
+ PyObject* moduleName;
+ char* className = PyExceptionClass_Name(exception);
+ if (className != NULL) {
+ char *dot = strrchr(className, '.');
+ if (dot != NULL)
+ className = dot+1;
+ }
+
+ moduleName = PyObject_GetAttrString(exception, "__module__");
+ if (moduleName == NULL)
+ err = PyFile_WriteString("<unknown>", f);
+ else {
+ char* modstr = PyString_AsString(moduleName);
+ if (modstr && strcmp(modstr, "exceptions"))
+ {
+ err = PyFile_WriteString(modstr, f);
+ err += PyFile_WriteString(".", f);
+ }
+ Py_DECREF(moduleName);
+ }
+ if (err == 0) {
+ if (className == NULL)
+ err = PyFile_WriteString("<unknown>", f);
+ else
+ err = PyFile_WriteString(className, f);
+ }
+ }
+ else
+ err = PyFile_WriteObject(exception, f, Py_PRINT_RAW);
+ if (err == 0 && (value != Py_None)) {
+ PyObject *s = PyObject_Str(value);
+ /* only print colon if the str() of the
+ object is not the empty string
+ */
+ if (s == NULL) {
+ PyErr_Clear();
+ err = -1;
+ PyFile_WriteString(": <exception str() failed>", f);
+ }
+ else if (!PyString_Check(s) ||
+ PyString_GET_SIZE(s) != 0)
+ err = PyFile_WriteString(": ", f);
+ if (err == 0)
+ err = PyFile_WriteObject(s, f, Py_PRINT_RAW);
+ Py_XDECREF(s);
+ }
+ /* try to write a newline in any case */
+ if (err < 0) {
+ PyErr_Clear();
+ }
+ err += PyFile_WriteString("\n", f);
+ }
+ Py_DECREF(value);
+ /* If an error happened here, don't show it.
+ XXX This is wrong, but too many callers rely on this behavior. */
+ if (err != 0)
+ PyErr_Clear();
+}
+
+PyObject *
+PyRun_StringFlags(const char *str, int start, PyObject *globals,
+ PyObject *locals, PyCompilerFlags *flags)
+{
+ PyObject *ret = NULL;
+ mod_ty mod;
+ PyArena *arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+
+ mod = PyParser_ASTFromString(str, "<string>", start, flags, arena);
+ if (mod != NULL)
+ ret = run_mod(mod, "<string>", globals, locals, flags, arena);
+ PyArena_Free(arena);
+ return ret;
+}
+
+PyObject *
+PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,
+ PyObject *locals, int closeit, PyCompilerFlags *flags)
+{
+ PyObject *ret;
+ mod_ty mod;
+ PyArena *arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+
+ mod = PyParser_ASTFromFile(fp, filename, start, 0, 0,
+ flags, NULL, arena);
+ if (closeit)
+ fclose(fp);
+ if (mod == NULL) {
+ PyArena_Free(arena);
+ return NULL;
+ }
+ ret = run_mod(mod, filename, globals, locals, flags, arena);
+ PyArena_Free(arena);
+ return ret;
+}
+
+static PyObject *
+run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals,
+ PyCompilerFlags *flags, PyArena *arena)
+{
+ PyCodeObject *co;
+ PyObject *v;
+ co = PyAST_Compile(mod, filename, flags, arena);
+ if (co == NULL)
+ return NULL;
+ v = PyEval_EvalCode(co, globals, locals);
+ Py_DECREF(co);
+ return v;
+}
+
+static PyObject *
+run_pyc_file(FILE *fp, const char *filename, PyObject *globals,
+ PyObject *locals, PyCompilerFlags *flags)
+{
+ PyCodeObject *co;
+ PyObject *v;
+ long magic;
+ long PyImport_GetMagicNumber(void);
+
+ magic = PyMarshal_ReadLongFromFile(fp);
+ if (magic != PyImport_GetMagicNumber()) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Bad magic number in .pyc file");
+ return NULL;
+ }
+ (void) PyMarshal_ReadLongFromFile(fp);
+ v = PyMarshal_ReadLastObjectFromFile(fp);
+ fclose(fp);
+ if (v == NULL || !PyCode_Check(v)) {
+ Py_XDECREF(v);
+ PyErr_SetString(PyExc_RuntimeError,
+ "Bad code object in .pyc file");
+ return NULL;
+ }
+ co = (PyCodeObject *)v;
+ v = PyEval_EvalCode(co, globals, locals);
+ if (v && flags)
+ flags->cf_flags |= (co->co_flags & PyCF_MASK);
+ Py_DECREF(co);
+ return v;
+}
+
+PyObject *
+Py_CompileStringFlags(const char *str, const char *filename, int start,
+ PyCompilerFlags *flags)
+{
+ PyCodeObject *co;
+ mod_ty mod;
+ PyArena *arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+
+ mod = PyParser_ASTFromString(str, filename, start, flags, arena);
+ if (mod == NULL) {
+ PyArena_Free(arena);
+ return NULL;
+ }
+ if (flags && (flags->cf_flags & PyCF_ONLY_AST)) {
+ PyObject *result = PyAST_mod2obj(mod);
+ PyArena_Free(arena);
+ return result;
+ }
+ co = PyAST_Compile(mod, filename, flags, arena);
+ PyArena_Free(arena);
+ return (PyObject *)co;
+}
+
+struct symtable *
+Py_SymtableString(const char *str, const char *filename, int start)
+{
+ struct symtable *st;
+ mod_ty mod;
+ PyCompilerFlags flags;
+ PyArena *arena = PyArena_New();
+ if (arena == NULL)
+ return NULL;
+
+ flags.cf_flags = 0;
+
+ mod = PyParser_ASTFromString(str, filename, start, &flags, arena);
+ if (mod == NULL) {
+ PyArena_Free(arena);
+ return NULL;
+ }
+ st = PySymtable_Build(mod, filename, 0);
+ PyArena_Free(arena);
+ return st;
+}
+
+/* Preferred access to parser is through AST. */
+mod_ty
+PyParser_ASTFromString(const char *s, const char *filename, int start,
+ PyCompilerFlags *flags, PyArena *arena)
+{
+ mod_ty mod;
+ PyCompilerFlags localflags;
+ perrdetail err;
+ int iflags = PARSER_FLAGS(flags);
+
+ node *n = PyParser_ParseStringFlagsFilenameEx(s, filename,
+ &_PyParser_Grammar, start, &err,
+ &iflags);
+ if (flags == NULL) {
+ localflags.cf_flags = 0;
+ flags = &localflags;
+ }
+ if (n) {
+ flags->cf_flags |= iflags & PyCF_MASK;
+ mod = PyAST_FromNode(n, flags, filename, arena);
+ PyNode_Free(n);
+ return mod;
+ }
+ else {
+ err_input(&err);
+ return NULL;
+ }
+}
+
+mod_ty
+PyParser_ASTFromFile(FILE *fp, const char *filename, int start, char *ps1,
+ char *ps2, PyCompilerFlags *flags, int *errcode,
+ PyArena *arena)
+{
+ mod_ty mod;
+ PyCompilerFlags localflags;
+ perrdetail err;
+ int iflags = PARSER_FLAGS(flags);
+
+ node *n = PyParser_ParseFileFlagsEx(fp, filename, &_PyParser_Grammar,
+ start, ps1, ps2, &err, &iflags);
+ if (flags == NULL) {
+ localflags.cf_flags = 0;
+ flags = &localflags;
+ }
+ if (n) {
+ flags->cf_flags |= iflags & PyCF_MASK;
+ mod = PyAST_FromNode(n, flags, filename, arena);
+ PyNode_Free(n);
+ return mod;
+ }
+ else {
+ err_input(&err);
+ if (errcode)
+ *errcode = err.error;
+ return NULL;
+ }
+}
+
+/* Simplified interface to parsefile -- return node or set exception */
+
+node *
+PyParser_SimpleParseFileFlags(FILE *fp, const char *filename, int start, int flags)
+{
+ perrdetail err;
+ node *n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar,
+ start, NULL, NULL, &err, flags);
+ if (n == NULL)
+ err_input(&err);
+
+ return n;
+}
+
+/* Simplified interface to parsestring -- return node or set exception */
+
+node *
+PyParser_SimpleParseStringFlags(const char *str, int start, int flags)
+{
+ perrdetail err;
+ node *n = PyParser_ParseStringFlags(str, &_PyParser_Grammar,
+ start, &err, flags);
+ if (n == NULL)
+ err_input(&err);
+ return n;
+}
+
+node *
+PyParser_SimpleParseStringFlagsFilename(const char *str, const char *filename,
+ int start, int flags)
+{
+ perrdetail err;
+ node *n = PyParser_ParseStringFlagsFilename(str, filename,
+ &_PyParser_Grammar, start, &err, flags);
+ if (n == NULL)
+ err_input(&err);
+ return n;
+}
+
+node *
+PyParser_SimpleParseStringFilename(const char *str, const char *filename, int start)
+{
+ return PyParser_SimpleParseStringFlagsFilename(str, filename, start, 0);
+}
+
+/* May want to move a more generalized form of this to parsetok.c or
+ even parser modules. */
+
+void
+PyParser_SetError(perrdetail *err)
+{
+ err_input(err);
+}
+
+/* Set the error appropriate to the given input error code (see errcode.h) */
+
+static void
+err_input(perrdetail *err)
+{
+ PyObject *v, *w, *errtype;
+ PyObject* u = NULL;
+ char *msg = NULL;
+ errtype = PyExc_SyntaxError;
+ switch (err->error) {
+ case E_ERROR:
+ goto cleanup;
+ case E_SYNTAX:
+ errtype = PyExc_IndentationError;
+ if (err->expected == INDENT)
+ msg = "expected an indented block";
+ else if (err->token == INDENT)
+ msg = "unexpected indent";
+ else if (err->token == DEDENT)
+ msg = "unexpected unindent";
+ else {
+ errtype = PyExc_SyntaxError;
+ msg = "invalid syntax";
+ }
+ break;
+ case E_TOKEN:
+ msg = "invalid token";
+ break;
+ case E_EOFS:
+ msg = "EOF while scanning triple-quoted string literal";
+ break;
+ case E_EOLS:
+ msg = "EOL while scanning string literal";
+ break;
+ case E_INTR:
+ if (!PyErr_Occurred())
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ goto cleanup;
+ case E_NOMEM:
+ PyErr_NoMemory();
+ goto cleanup;
+ case E_EOF:
+ msg = "unexpected EOF while parsing";
+ break;
+ case E_TABSPACE:
+ errtype = PyExc_TabError;
+ msg = "inconsistent use of tabs and spaces in indentation";
+ break;
+ case E_OVERFLOW:
+ msg = "expression too long";
+ break;
+ case E_DEDENT:
+ errtype = PyExc_IndentationError;
+ msg = "unindent does not match any outer indentation level";
+ break;
+ case E_TOODEEP:
+ errtype = PyExc_IndentationError;
+ msg = "too many levels of indentation";
+ break;
+ case E_DECODE: {
+ PyObject *type, *value, *tb;
+ PyErr_Fetch(&type, &value, &tb);
+ if (value != NULL) {
+ u = PyObject_Str(value);
+ if (u != NULL) {
+ msg = PyString_AsString(u);
+ }
+ }
+ if (msg == NULL)
+ msg = "unknown decode error";
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(tb);
+ break;
+ }
+ case E_IO:
+ msg = "I/O error while reading";
+ break;
+ case E_LINECONT:
+ msg = "unexpected character after line continuation character";
+ break;
+ default:
+ fprintf(stderr, "error=%d\n", err->error);
+ msg = "unknown parsing error";
+ break;
+ }
+ v = Py_BuildValue("(ziiz)", err->filename,
+ err->lineno, err->offset, err->text);
+ w = NULL;
+ if (v != NULL)
+ w = Py_BuildValue("(sO)", msg, v);
+ Py_XDECREF(u);
+ Py_XDECREF(v);
+ PyErr_SetObject(errtype, w);
+ Py_XDECREF(w);
+cleanup:
+ if (err->text != NULL) {
+ PyObject_FREE(err->text);
+ err->text = NULL;
+ }
+}
+
+/* Print fatal error message and abort */
+
+void
+Py_FatalError(const char *msg)
+{
+ fprintf(stderr, "Fatal Python error: %s\n", msg);
+ fflush(stderr); /* it helps in Windows debug build */
+
+#ifdef MS_WINDOWS
+ {
+ size_t len = strlen(msg);
+ WCHAR* buffer;
+ size_t i;
+
+ /* Convert the message to wchar_t. This uses a simple one-to-one
+ conversion, assuming that the this error message actually uses ASCII
+ only. If this ceases to be true, we will have to convert. */
+ buffer = alloca( (len+1) * (sizeof *buffer));
+ for( i=0; i<=len; ++i)
+ buffer[i] = msg[i];
+ OutputDebugStringW(L"Fatal Python error: ");
+ OutputDebugStringW(buffer);
+ OutputDebugStringW(L"\n");
+ }
+#ifdef _DEBUG
+ DebugBreak();
+#endif
+#endif /* MS_WINDOWS */
+ abort();
+}
+
+/* Clean up and exit */
+
+#ifdef WITH_THREAD
+#include "pythread.h"
+#endif
+
+/* Wait until threading._shutdown completes, provided
+ the threading module was imported in the first place.
+ The shutdown routine will wait until all non-daemon
+ "threading" threads have completed. */
+static void
+wait_for_thread_shutdown(void)
+{
+#ifdef WITH_THREAD
+ PyObject *result;
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
+ "threading");
+ if (threading == NULL) {
+ /* threading not imported */
+ PyErr_Clear();
+ return;
+ }
+ result = PyObject_CallMethod(threading, "_shutdown", "");
+ if (result == NULL)
+ PyErr_WriteUnraisable(threading);
+ else
+ Py_DECREF(result);
+ Py_DECREF(threading);
+#endif
+}
+
+#define NEXITFUNCS 32
+static void (*exitfuncs[NEXITFUNCS])(void);
+static int nexitfuncs = 0;
+
+int Py_AtExit(void (*func)(void))
+{
+ if (nexitfuncs >= NEXITFUNCS)
+ return -1;
+ exitfuncs[nexitfuncs++] = func;
+ return 0;
+}
+
+static void
+call_sys_exitfunc(void)
+{
+ PyObject *exitfunc = PySys_GetObject("exitfunc");
+
+ if (exitfunc) {
+ PyObject *res;
+ Py_INCREF(exitfunc);
+ PySys_SetObject("exitfunc", (PyObject *)NULL);
+ res = PyEval_CallObject(exitfunc, (PyObject *)NULL);
+ if (res == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
+ PySys_WriteStderr("Error in sys.exitfunc:\n");
+ }
+ PyErr_Print();
+ }
+ Py_DECREF(exitfunc);
+ }
+
+ if (Py_FlushLine())
+ PyErr_Clear();
+}
+
+static void
+call_ll_exitfuncs(void)
+{
+ while (nexitfuncs > 0)
+ (*exitfuncs[--nexitfuncs])();
+
+ fflush(stdout);
+ fflush(stderr);
+}
+
+void
+Py_Exit(int sts)
+{
+ Py_Finalize();
+
+ exit(sts);
+}
+
+static void
+initsigs(void)
+{
+#ifdef SIGPIPE
+ PyOS_setsig(SIGPIPE, SIG_IGN);
+#endif
+#ifdef SIGXFZ
+ PyOS_setsig(SIGXFZ, SIG_IGN);
+#endif
+#ifdef SIGXFSZ
+ PyOS_setsig(SIGXFSZ, SIG_IGN);
+#endif
+ PyOS_InitInterrupts(); /* May imply initsignal() */
+}
+
+
+/*
+ * The file descriptor fd is considered ``interactive'' if either
+ * a) isatty(fd) is TRUE, or
+ * b) the -i flag was given, and the filename associated with
+ * the descriptor is NULL or "<stdin>" or "???".
+ */
+int
+Py_FdIsInteractive(FILE *fp, const char *filename)
+{
+ if (isatty((int)fileno(fp)))
+ return 1;
+ if (!Py_InteractiveFlag)
+ return 0;
+ return (filename == NULL) ||
+ (strcmp(filename, "<stdin>") == 0) ||
+ (strcmp(filename, "???") == 0);
+}
+
+
+#if defined(USE_STACKCHECK)
+#if defined(WIN32) && defined(_MSC_VER)
+
+/* Stack checking for Microsoft C */
+
+#include <malloc.h>
+#include <excpt.h>
+
+/*
+ * Return non-zero when we run out of memory on the stack; zero otherwise.
+ */
+int
+PyOS_CheckStack(void)
+{
+ __try {
+ /* alloca throws a stack overflow exception if there's
+ not enough space left on the stack */
+ alloca(PYOS_STACK_MARGIN * sizeof(void*));
+ return 0;
+ } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ?
+ EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH) {
+ int errcode = _resetstkoflw();
+ if (errcode == 0)
+ {
+ Py_FatalError("Could not reset the stack!");
+ }
+ }
+ return 1;
+}
+
+#endif /* WIN32 && _MSC_VER */
+
+/* Alternate implementations can be added here... */
+
+#endif /* USE_STACKCHECK */
+
+
+/* Wrappers around sigaction() or signal(). */
+
+PyOS_sighandler_t
+PyOS_getsig(int sig)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction context;
+ if (sigaction(sig, NULL, &context) == -1)
+ return SIG_ERR;
+ return context.sa_handler;
+#else
+ PyOS_sighandler_t handler;
+/* Special signal handling for the secure CRT in Visual Studio 2005 */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ switch (sig) {
+ /* Only these signals are valid */
+ case SIGINT:
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGBREAK:
+ case SIGABRT:
+ break;
+ /* Don't call signal() with other values or it will assert */
+ default:
+ return SIG_ERR;
+ }
+#endif /* _MSC_VER && _MSC_VER >= 1400 */
+ handler = signal(sig, SIG_IGN);
+ if (handler != SIG_ERR)
+ signal(sig, handler);
+ return handler;
+#endif
+}
+
+PyOS_sighandler_t
+PyOS_setsig(int sig, PyOS_sighandler_t handler)
+{
+#ifdef HAVE_SIGACTION
+ /* Some code in Modules/signalmodule.c depends on sigaction() being
+ * used here if HAVE_SIGACTION is defined. Fix that if this code
+ * changes to invalidate that assumption.
+ */
+ struct sigaction context, ocontext;
+ context.sa_handler = handler;
+ sigemptyset(&context.sa_mask);
+ context.sa_flags = 0;
+ if (sigaction(sig, &context, &ocontext) == -1)
+ return SIG_ERR;
+ return ocontext.sa_handler;
+#else
+ PyOS_sighandler_t oldhandler;
+ oldhandler = signal(sig, handler);
+#ifdef HAVE_SIGINTERRUPT
+ siginterrupt(sig, 1);
+#endif
+ return oldhandler;
+#endif
+}
+
+/* Deprecated C API functions still provided for binary compatibility */
+
+#undef PyParser_SimpleParseFile
+PyAPI_FUNC(node *)
+PyParser_SimpleParseFile(FILE *fp, const char *filename, int start)
+{
+ return PyParser_SimpleParseFileFlags(fp, filename, start, 0);
+}
+
+#undef PyParser_SimpleParseString
+PyAPI_FUNC(node *)
+PyParser_SimpleParseString(const char *str, int start)
+{
+ return PyParser_SimpleParseStringFlags(str, start, 0);
+}
+
+#undef PyRun_AnyFile
+PyAPI_FUNC(int)
+PyRun_AnyFile(FILE *fp, const char *name)
+{
+ return PyRun_AnyFileExFlags(fp, name, 0, NULL);
+}
+
+#undef PyRun_AnyFileEx
+PyAPI_FUNC(int)
+PyRun_AnyFileEx(FILE *fp, const char *name, int closeit)
+{
+ return PyRun_AnyFileExFlags(fp, name, closeit, NULL);
+}
+
+#undef PyRun_AnyFileFlags
+PyAPI_FUNC(int)
+PyRun_AnyFileFlags(FILE *fp, const char *name, PyCompilerFlags *flags)
+{
+ return PyRun_AnyFileExFlags(fp, name, 0, flags);
+}
+
+#undef PyRun_File
+PyAPI_FUNC(PyObject *)
+PyRun_File(FILE *fp, const char *p, int s, PyObject *g, PyObject *l)
+{
+ return PyRun_FileExFlags(fp, p, s, g, l, 0, NULL);
+}
+
+#undef PyRun_FileEx
+PyAPI_FUNC(PyObject *)
+PyRun_FileEx(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, int c)
+{
+ return PyRun_FileExFlags(fp, p, s, g, l, c, NULL);
+}
+
+#undef PyRun_FileFlags
+PyAPI_FUNC(PyObject *)
+PyRun_FileFlags(FILE *fp, const char *p, int s, PyObject *g, PyObject *l,
+ PyCompilerFlags *flags)
+{
+ return PyRun_FileExFlags(fp, p, s, g, l, 0, flags);
+}
+
+#undef PyRun_SimpleFile
+PyAPI_FUNC(int)
+PyRun_SimpleFile(FILE *f, const char *p)
+{
+ return PyRun_SimpleFileExFlags(f, p, 0, NULL);
+}
+
+#undef PyRun_SimpleFileEx
+PyAPI_FUNC(int)
+PyRun_SimpleFileEx(FILE *f, const char *p, int c)
+{
+ return PyRun_SimpleFileExFlags(f, p, c, NULL);
+}
+
+
+#undef PyRun_String
+PyAPI_FUNC(PyObject *)
+PyRun_String(const char *str, int s, PyObject *g, PyObject *l)
+{
+ return PyRun_StringFlags(str, s, g, l, NULL);
+}
+
+#undef PyRun_SimpleString
+PyAPI_FUNC(int)
+PyRun_SimpleString(const char *s)
+{
+ return PyRun_SimpleStringFlags(s, NULL);
+}
+
+#undef Py_CompileString
+PyAPI_FUNC(PyObject *)
+Py_CompileString(const char *str, const char *p, int s)
+{
+ return Py_CompileStringFlags(str, p, s, NULL);
+}
+
+#undef PyRun_InteractiveOne
+PyAPI_FUNC(int)
+PyRun_InteractiveOne(FILE *f, const char *p)
+{
+ return PyRun_InteractiveOneFlags(f, p, NULL);
+}
+
+#undef PyRun_InteractiveLoop
+PyAPI_FUNC(int)
+PyRun_InteractiveLoop(FILE *f, const char *p)
+{
+ return PyRun_InteractiveLoopFlags(f, p, NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/contrib/tools/python/src/Python/random.c b/contrib/tools/python/src/Python/random.c
new file mode 100644
index 0000000000..d80ff40523
--- /dev/null
+++ b/contrib/tools/python/src/Python/random.c
@@ -0,0 +1,435 @@
+#include "Python.h"
+#ifdef MS_WINDOWS
+#include <windows.h>
+#include <wincrypt.h>
+#else
+#include <fcntl.h>
+#if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY))
+#include <sys/random.h>
+#endif
+#endif
+
+#ifdef Py_DEBUG
+int _Py_HashSecret_Initialized = 0;
+#else
+static int _Py_HashSecret_Initialized = 0;
+#endif
+
+#ifdef MS_WINDOWS
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
+ LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
+ DWORD dwFlags );
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
+ BYTE *pbBuffer );
+
+static CRYPTGENRANDOM pCryptGenRandom = NULL;
+/* This handle is never explicitly released. Instead, the operating
+ system will release it when the process terminates. */
+static HCRYPTPROV hCryptProv = 0;
+
+static int
+win32_urandom_init(int raise)
+{
+ HINSTANCE hAdvAPI32 = NULL;
+ CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
+
+ /* Obtain handle to the DLL containing CryptoAPI. This should not fail. */
+ hAdvAPI32 = GetModuleHandle("advapi32.dll");
+ if(hAdvAPI32 == NULL)
+ goto error;
+
+ /* Obtain pointers to the CryptoAPI functions. This will fail on some early
+ versions of Win95. */
+ pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(
+ hAdvAPI32, "CryptAcquireContextA");
+ if (pCryptAcquireContext == NULL)
+ goto error;
+
+ pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32,
+ "CryptGenRandom");
+ if (pCryptGenRandom == NULL)
+ goto error;
+
+ /* Acquire context */
+ if (! pCryptAcquireContext(&hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ goto error;
+
+ return 0;
+
+error:
+ if (raise)
+ PyErr_SetFromWindowsErr(0);
+ else
+ Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
+ return -1;
+}
+
+/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
+ API. Return 0 on success, or -1 on error. */
+static int
+win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
+{
+ Py_ssize_t chunk;
+
+ if (hCryptProv == 0)
+ {
+ if (win32_urandom_init(raise) == -1)
+ return -1;
+ }
+
+ while (size > 0)
+ {
+ chunk = size > INT_MAX ? INT_MAX : size;
+ if (!pCryptGenRandom(hCryptProv, chunk, buffer))
+ {
+ /* CryptGenRandom() failed */
+ if (raise)
+ PyErr_SetFromWindowsErr(0);
+ else
+ Py_FatalError("Failed to initialized the randomized hash "
+ "secret using CryptoGen)");
+ return -1;
+ }
+ buffer += chunk;
+ size -= chunk;
+ }
+ return 0;
+}
+
+/* Issue #25003: Don't use getentropy() on Solaris (available since
+ Solaris 11.3), it is blocking whereas os.urandom() should not block.
+
+ Issue #29188: Don't use getentropy() on Linux since the glibc 2.24
+ implements it with the getrandom() syscall which can fail with ENOSYS,
+ and this error is not supported in py_getentropy() and getrandom() is called
+ with flags=0 which blocks until system urandom is initialized, which is not
+ the desired behaviour to seed the Python hash secret nor for os.urandom():
+ see the PEP 524 which was only implemented in Python 3.6. */
+#elif defined(HAVE_GETENTROPY) && !defined(sun) && !defined(linux)
+#define PY_GETENTROPY 1
+
+/* Fill buffer with size pseudo-random bytes generated by getentropy().
+ Return 0 on success, or raise an exception and return -1 on error.
+ If fatal is nonzero, call Py_FatalError() instead of raising an exception
+ on error. */
+static int
+py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
+{
+ while (size > 0) {
+ Py_ssize_t len = size < 256 ? size : 256;
+ int res;
+
+ if (!fatal) {
+ Py_BEGIN_ALLOW_THREADS
+ res = getentropy(buffer, len);
+ Py_END_ALLOW_THREADS
+
+ if (res < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+ }
+ else {
+ res = getentropy(buffer, len);
+ if (res < 0)
+ Py_FatalError("getentropy() failed");
+ }
+
+ buffer += len;
+ size -= len;
+ }
+ return 0;
+}
+#endif
+
+#ifdef __VMS
+/* Use openssl random routine */
+#include <openssl/rand.h>
+static int
+vms_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
+{
+ if (RAND_pseudo_bytes(buffer, size) < 0) {
+ if (raise) {
+ PyErr_Format(PyExc_ValueError,
+ "RAND_pseudo_bytes");
+ } else {
+ Py_FatalError("Failed to initialize the randomized hash "
+ "secret using RAND_pseudo_bytes");
+ }
+ return -1;
+ }
+ return 0;
+}
+#endif /* __VMS */
+
+
+#if !defined(MS_WINDOWS) && !defined(__VMS)
+
+static struct {
+ int fd;
+ dev_t st_dev;
+ ino_t st_ino;
+} urandom_cache = { -1 };
+
+/* Read size bytes from /dev/urandom into buffer.
+ Call Py_FatalError() on error. */
+static void
+dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
+{
+ int fd;
+ Py_ssize_t n;
+
+ assert (0 < size);
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ Py_FatalError("Failed to open /dev/urandom");
+
+ while (0 < size)
+ {
+ do {
+ n = read(fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+ if (n <= 0)
+ {
+ /* stop on error or if read(size) returned 0 */
+ Py_FatalError("Failed to read bytes from /dev/urandom");
+ break;
+ }
+ buffer += n;
+ size -= (Py_ssize_t)n;
+ }
+ close(fd);
+}
+
+/* Read size bytes from /dev/urandom into buffer.
+ Return 0 on success, raise an exception and return -1 on error. */
+static int
+dev_urandom_python(char *buffer, Py_ssize_t size)
+{
+ int fd;
+ Py_ssize_t n;
+ struct stat st;
+ int attr;
+
+ if (size <= 0)
+ return 0;
+
+ if (urandom_cache.fd >= 0) {
+ /* Does the fd point to the same thing as before? (issue #21207) */
+ if (fstat(urandom_cache.fd, &st)
+ || st.st_dev != urandom_cache.st_dev
+ || st.st_ino != urandom_cache.st_ino) {
+ /* Something changed: forget the cached fd (but don't close it,
+ since it probably points to something important for some
+ third-party code). */
+ urandom_cache.fd = -1;
+ }
+ }
+ if (urandom_cache.fd >= 0)
+ fd = urandom_cache.fd;
+ else {
+ Py_BEGIN_ALLOW_THREADS
+ fd = open("/dev/urandom", O_RDONLY);
+ Py_END_ALLOW_THREADS
+ if (fd < 0)
+ {
+ if (errno == ENOENT || errno == ENXIO ||
+ errno == ENODEV || errno == EACCES)
+ PyErr_SetString(PyExc_NotImplementedError,
+ "/dev/urandom (or equivalent) not found");
+ else
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+
+ /* try to make the file descriptor non-inheritable, ignore errors */
+ attr = fcntl(fd, F_GETFD);
+ if (attr >= 0) {
+ attr |= FD_CLOEXEC;
+ (void)fcntl(fd, F_SETFD, attr);
+ }
+
+ if (urandom_cache.fd >= 0) {
+ /* urandom_fd was initialized by another thread while we were
+ not holding the GIL, keep it. */
+ close(fd);
+ fd = urandom_cache.fd;
+ }
+ else {
+ if (fstat(fd, &st)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ close(fd);
+ return -1;
+ }
+ else {
+ urandom_cache.fd = fd;
+ urandom_cache.st_dev = st.st_dev;
+ urandom_cache.st_ino = st.st_ino;
+ }
+ }
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ do {
+ do {
+ n = read(fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+ if (n <= 0)
+ break;
+ buffer += n;
+ size -= (Py_ssize_t)n;
+ } while (0 < size);
+ Py_END_ALLOW_THREADS
+
+ if (n <= 0)
+ {
+ /* stop on error or if read(size) returned 0 */
+ if (n < 0)
+ PyErr_SetFromErrno(PyExc_OSError);
+ else
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to read %zi bytes from /dev/urandom",
+ size);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+dev_urandom_close(void)
+{
+ if (urandom_cache.fd >= 0) {
+ close(urandom_cache.fd);
+ urandom_cache.fd = -1;
+ }
+}
+
+
+#endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
+
+/* Fill buffer with pseudo-random bytes generated by a linear congruent
+ generator (LCG):
+
+ x(n+1) = (x(n) * 214013 + 2531011) % 2^32
+
+ Use bits 23..16 of x(n) to generate a byte. */
+static void
+lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
+{
+ size_t index;
+ unsigned int x;
+
+ x = x0;
+ for (index=0; index < size; index++) {
+ x *= 214013;
+ x += 2531011;
+ /* modulo 2 ^ (8 * sizeof(int)) */
+ buffer[index] = (x >> 16) & 0xff;
+ }
+}
+
+/* Fill buffer with size pseudo-random bytes from the operating system random
+ number generator (RNG). It is suitable for most cryptographic purposes
+ except long living private keys for asymmetric encryption.
+
+ Return 0 on success, raise an exception and return -1 on error. */
+int
+_PyOS_URandom(void *buffer, Py_ssize_t size)
+{
+ if (size < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "negative argument not allowed");
+ return -1;
+ }
+ if (size == 0)
+ return 0;
+
+#ifdef MS_WINDOWS
+ return win32_urandom((unsigned char *)buffer, size, 1);
+#elif defined(PY_GETENTROPY)
+ return py_getentropy(buffer, size, 0);
+#else
+# ifdef __VMS
+ return vms_urandom((unsigned char *)buffer, size, 1);
+# else
+ return dev_urandom_python((char*)buffer, size);
+# endif
+#endif
+}
+
+void
+_PyRandom_Init(void)
+{
+ char *env;
+ void *secret = &_Py_HashSecret;
+ Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
+
+ if (_Py_HashSecret_Initialized)
+ return;
+ _Py_HashSecret_Initialized = 1;
+
+ /*
+ By default, hash randomization is disabled, and only
+ enabled if PYTHONHASHSEED is set to non-empty or if
+ "-R" is provided at the command line:
+ */
+ if (!Py_HashRandomizationFlag) {
+ /* Disable the randomized hash: */
+ memset(secret, 0, secret_size);
+ return;
+ }
+
+ /*
+ Hash randomization is enabled. Generate a per-process secret,
+ using PYTHONHASHSEED if provided.
+ */
+
+ env = Py_GETENV("PYTHONHASHSEED");
+ if (env && *env != '\0' && strcmp(env, "random") != 0) {
+ char *endptr = env;
+ unsigned long seed;
+ seed = strtoul(env, &endptr, 10);
+ if (*endptr != '\0'
+ || seed > 4294967295UL
+ || (errno == ERANGE && seed == ULONG_MAX))
+ {
+ Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
+ "in range [0; 4294967295]");
+ }
+ if (seed == 0) {
+ /* disable the randomized hash */
+ memset(secret, 0, secret_size);
+ }
+ else {
+ lcg_urandom(seed, (unsigned char*)secret, secret_size);
+ }
+ }
+ else {
+#ifdef MS_WINDOWS
+ (void)win32_urandom((unsigned char *)secret, secret_size, 0);
+#elif __VMS
+ vms_urandom((unsigned char *)secret, secret_size, 0);
+#elif defined(PY_GETENTROPY)
+ (void)py_getentropy(secret, secret_size, 1);
+#else
+ dev_urandom_noraise(secret, secret_size);
+#endif
+ }
+}
+
+void
+_PyRandom_Fini(void)
+{
+#ifdef MS_WINDOWS
+ if (hCryptProv) {
+ CryptReleaseContext(hCryptProv, 0);
+ hCryptProv = 0;
+ }
+#elif defined(PY_GETENTROPY)
+ /* nothing to clean */
+#else
+ dev_urandom_close();
+#endif
+}
diff --git a/contrib/tools/python/src/Python/structmember.c b/contrib/tools/python/src/Python/structmember.c
new file mode 100644
index 0000000000..e347b51aac
--- /dev/null
+++ b/contrib/tools/python/src/Python/structmember.c
@@ -0,0 +1,363 @@
+
+/* Map C struct members to Python object attributes */
+
+#include "Python.h"
+
+#include "structmember.h"
+
+static PyObject *
+listmembers(struct memberlist *mlist)
+{
+ int i, n;
+ PyObject *v;
+ for (n = 0; mlist[n].name != NULL; n++)
+ ;
+ v = PyList_New(n);
+ if (v != NULL) {
+ for (i = 0; i < n; i++)
+ PyList_SetItem(v, i,
+ PyString_FromString(mlist[i].name));
+ if (PyErr_Occurred()) {
+ Py_DECREF(v);
+ v = NULL;
+ }
+ else {
+ PyList_Sort(v);
+ }
+ }
+ return v;
+}
+
+PyObject *
+PyMember_Get(const char *addr, struct memberlist *mlist, const char *name)
+{
+ struct memberlist *l;
+
+ if (strcmp(name, "__members__") == 0)
+ return listmembers(mlist);
+ for (l = mlist; l->name != NULL; l++) {
+ if (strcmp(l->name, name) == 0) {
+ PyMemberDef copy;
+ copy.name = l->name;
+ copy.type = l->type;
+ copy.offset = l->offset;
+ copy.flags = l->flags;
+ copy.doc = NULL;
+ return PyMember_GetOne(addr, &copy);
+ }
+ }
+ PyErr_SetString(PyExc_AttributeError, name);
+ return NULL;
+}
+
+PyObject *
+PyMember_GetOne(const char *addr, PyMemberDef *l)
+{
+ PyObject *v;
+ if ((l->flags & READ_RESTRICTED) &&
+ PyEval_GetRestricted()) {
+ PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
+ return NULL;
+ }
+ addr += l->offset;
+ switch (l->type) {
+ case T_BOOL:
+ v = PyBool_FromLong(*(char*)addr);
+ break;
+ case T_BYTE:
+ v = PyInt_FromLong(*(char*)addr);
+ break;
+ case T_UBYTE:
+ v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
+ break;
+ case T_SHORT:
+ v = PyInt_FromLong(*(short*)addr);
+ break;
+ case T_USHORT:
+ v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
+ break;
+ case T_INT:
+ v = PyInt_FromLong(*(int*)addr);
+ break;
+ case T_UINT:
+ v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
+ break;
+ case T_LONG:
+ v = PyInt_FromLong(*(long*)addr);
+ break;
+ case T_ULONG:
+ v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
+ break;
+ case T_PYSSIZET:
+ v = PyInt_FromSsize_t(*(Py_ssize_t*)addr);
+ break;
+ case T_FLOAT:
+ v = PyFloat_FromDouble((double)*(float*)addr);
+ break;
+ case T_DOUBLE:
+ v = PyFloat_FromDouble(*(double*)addr);
+ break;
+ case T_STRING:
+ if (*(char**)addr == NULL) {
+ Py_INCREF(Py_None);
+ v = Py_None;
+ }
+ else
+ v = PyString_FromString(*(char**)addr);
+ break;
+ case T_STRING_INPLACE:
+ v = PyString_FromString((char*)addr);
+ break;
+ case T_CHAR:
+ v = PyString_FromStringAndSize((char*)addr, 1);
+ break;
+ case T_OBJECT:
+ v = *(PyObject **)addr;
+ if (v == NULL)
+ v = Py_None;
+ Py_INCREF(v);
+ break;
+ case T_OBJECT_EX:
+ v = *(PyObject **)addr;
+ if (v == NULL)
+ PyErr_SetString(PyExc_AttributeError, l->name);
+ Py_XINCREF(v);
+ break;
+#ifdef HAVE_LONG_LONG
+ case T_LONGLONG:
+ v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr);
+ break;
+ case T_ULONGLONG:
+ v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr);
+ break;
+#endif /* HAVE_LONG_LONG */
+ default:
+ PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
+ v = NULL;
+ }
+ return v;
+}
+
+int
+PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v)
+{
+ struct memberlist *l;
+
+ for (l = mlist; l->name != NULL; l++) {
+ if (strcmp(l->name, name) == 0) {
+ PyMemberDef copy;
+ copy.name = l->name;
+ copy.type = l->type;
+ copy.offset = l->offset;
+ copy.flags = l->flags;
+ copy.doc = NULL;
+ return PyMember_SetOne(addr, &copy, v);
+ }
+ }
+
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+}
+
+#define WARN(msg) \
+ do { \
+ if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) \
+ return -1; \
+ } while (0)
+
+int
+PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
+{
+ PyObject *oldv;
+
+ addr += l->offset;
+
+ if ((l->flags & READONLY))
+ {
+ PyErr_SetString(PyExc_TypeError, "readonly attribute");
+ return -1;
+ }
+ if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) {
+ PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
+ return -1;
+ }
+ if (v == NULL) {
+ if (l->type == T_OBJECT_EX) {
+ /* Check if the attribute is set. */
+ if (*(PyObject **)addr == NULL) {
+ PyErr_SetString(PyExc_AttributeError, l->name);
+ return -1;
+ }
+ }
+ else if (l->type != T_OBJECT) {
+ PyErr_SetString(PyExc_TypeError,
+ "can't delete numeric/char attribute");
+ return -1;
+ }
+ }
+ switch (l->type) {
+ case T_BOOL:{
+ if (!PyBool_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "attribute value type must be bool");
+ return -1;
+ }
+ if (v == Py_True)
+ *(char*)addr = (char) 1;
+ else
+ *(char*)addr = (char) 0;
+ break;
+ }
+ case T_BYTE:{
+ long long_val = PyInt_AsLong(v);
+ if ((long_val == -1) && PyErr_Occurred())
+ return -1;
+ *(char*)addr = (char)long_val;
+ /* XXX: For compatibility, only warn about truncations
+ for now. */
+ if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
+ WARN("Truncation of value to char");
+ break;
+ }
+ case T_UBYTE:{
+ long long_val = PyInt_AsLong(v);
+ if ((long_val == -1) && PyErr_Occurred())
+ return -1;
+ *(unsigned char*)addr = (unsigned char)long_val;
+ if ((long_val > UCHAR_MAX) || (long_val < 0))
+ WARN("Truncation of value to unsigned char");
+ break;
+ }
+ case T_SHORT:{
+ long long_val = PyInt_AsLong(v);
+ if ((long_val == -1) && PyErr_Occurred())
+ return -1;
+ *(short*)addr = (short)long_val;
+ if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
+ WARN("Truncation of value to short");
+ break;
+ }
+ case T_USHORT:{
+ long long_val = PyInt_AsLong(v);
+ if ((long_val == -1) && PyErr_Occurred())
+ return -1;
+ *(unsigned short*)addr = (unsigned short)long_val;
+ if ((long_val > USHRT_MAX) || (long_val < 0))
+ WARN("Truncation of value to unsigned short");
+ break;
+ }
+ case T_INT:{
+ long long_val = PyInt_AsLong(v);
+ if ((long_val == -1) && PyErr_Occurred())
+ return -1;
+ *(int *)addr = (int)long_val;
+ if ((long_val > INT_MAX) || (long_val < INT_MIN))
+ WARN("Truncation of value to int");
+ break;
+ }
+ case T_UINT:{
+ unsigned long ulong_val = PyLong_AsUnsignedLong(v);
+ if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
+ /* XXX: For compatibility, accept negative int values
+ as well. */
+ PyErr_Clear();
+ ulong_val = PyLong_AsLong(v);
+ if ((ulong_val == (unsigned long)-1) &&
+ PyErr_Occurred())
+ return -1;
+ *(unsigned int *)addr = (unsigned int)ulong_val;
+ WARN("Writing negative value into unsigned field");
+ } else
+ *(unsigned int *)addr = (unsigned int)ulong_val;
+ if (ulong_val > UINT_MAX)
+ WARN("Truncation of value to unsigned int");
+ break;
+ }
+ case T_LONG:{
+ *(long*)addr = PyLong_AsLong(v);
+ if ((*(long*)addr == -1) && PyErr_Occurred())
+ return -1;
+ break;
+ }
+ case T_ULONG:{
+ *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
+ if ((*(unsigned long*)addr == (unsigned long)-1)
+ && PyErr_Occurred()) {
+ /* XXX: For compatibility, accept negative int values
+ as well. */
+ PyErr_Clear();
+ *(unsigned long*)addr = PyLong_AsLong(v);
+ if ((*(unsigned long*)addr == (unsigned long)-1)
+ && PyErr_Occurred())
+ return -1;
+ WARN("Writing negative value into unsigned field");
+ }
+ break;
+ }
+ case T_PYSSIZET:{
+ *(Py_ssize_t*)addr = PyInt_AsSsize_t(v);
+ if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
+ && PyErr_Occurred())
+ return -1;
+ break;
+ }
+ case T_FLOAT:{
+ double double_val = PyFloat_AsDouble(v);
+ if ((double_val == -1) && PyErr_Occurred())
+ return -1;
+ *(float*)addr = (float)double_val;
+ break;
+ }
+ case T_DOUBLE:
+ *(double*)addr = PyFloat_AsDouble(v);
+ if ((*(double*)addr == -1) && PyErr_Occurred())
+ return -1;
+ break;
+ case T_OBJECT:
+ case T_OBJECT_EX:
+ Py_XINCREF(v);
+ oldv = *(PyObject **)addr;
+ *(PyObject **)addr = v;
+ Py_XDECREF(oldv);
+ break;
+ case T_CHAR:
+ if (PyString_Check(v) && PyString_Size(v) == 1) {
+ *(char*)addr = PyString_AsString(v)[0];
+ }
+ else {
+ PyErr_BadArgument();
+ return -1;
+ }
+ break;
+ case T_STRING:
+ case T_STRING_INPLACE:
+ PyErr_SetString(PyExc_TypeError, "readonly attribute");
+ return -1;
+#ifdef HAVE_LONG_LONG
+ case T_LONGLONG:{
+ PY_LONG_LONG value;
+ *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v);
+ if ((value == -1) && PyErr_Occurred())
+ return -1;
+ break;
+ }
+ case T_ULONGLONG:{
+ unsigned PY_LONG_LONG value;
+ /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
+ doesn't ??? */
+ if (PyLong_Check(v))
+ *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v);
+ else
+ *(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v);
+ if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred())
+ return -1;
+ break;
+ }
+#endif /* HAVE_LONG_LONG */
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "bad memberdescr type for %s", l->name);
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/tools/python/src/Python/symtable.c b/contrib/tools/python/src/Python/symtable.c
new file mode 100644
index 0000000000..23aeaaa76f
--- /dev/null
+++ b/contrib/tools/python/src/Python/symtable.c
@@ -0,0 +1,1612 @@
+#include "Python.h"
+#include "Python-ast.h"
+#include "code.h"
+#include "symtable.h"
+#include "structmember.h"
+
+/* error strings used for warnings */
+#define GLOBAL_AFTER_ASSIGN \
+"name '%.400s' is assigned to before global declaration"
+
+#define GLOBAL_AFTER_USE \
+"name '%.400s' is used prior to global declaration"
+
+#define IMPORT_STAR_WARNING "import * only allowed at module level"
+
+#define RETURN_VAL_IN_GENERATOR \
+ "'return' with argument inside generator"
+
+
+static PySTEntryObject *
+ste_new(struct symtable *st, identifier name, _Py_block_ty block,
+ void *key, int lineno)
+{
+ PySTEntryObject *ste = NULL;
+ PyObject *k = NULL;
+
+ k = PyLong_FromVoidPtr(key);
+ if (k == NULL)
+ goto fail;
+ ste = PyObject_New(PySTEntryObject, &PySTEntry_Type);
+ if (ste == NULL) {
+ Py_DECREF(k);
+ goto fail;
+ }
+ ste->ste_table = st;
+ ste->ste_id = k; /* ste owns reference to k */
+
+ ste->ste_name = name;
+ Py_INCREF(name);
+
+ ste->ste_symbols = NULL;
+ ste->ste_varnames = NULL;
+ ste->ste_children = NULL;
+
+ ste->ste_symbols = PyDict_New();
+ if (ste->ste_symbols == NULL)
+ goto fail;
+
+ ste->ste_varnames = PyList_New(0);
+ if (ste->ste_varnames == NULL)
+ goto fail;
+
+ ste->ste_children = PyList_New(0);
+ if (ste->ste_children == NULL)
+ goto fail;
+
+ ste->ste_type = block;
+ ste->ste_unoptimized = 0;
+ ste->ste_nested = 0;
+ ste->ste_free = 0;
+ ste->ste_varargs = 0;
+ ste->ste_varkeywords = 0;
+ ste->ste_opt_lineno = 0;
+ ste->ste_tmpname = 0;
+ ste->ste_lineno = lineno;
+
+ if (st->st_cur != NULL &&
+ (st->st_cur->ste_nested ||
+ st->st_cur->ste_type == FunctionBlock))
+ ste->ste_nested = 1;
+ ste->ste_child_free = 0;
+ ste->ste_generator = 0;
+ ste->ste_returns_value = 0;
+
+ if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
+ goto fail;
+
+ return ste;
+ fail:
+ Py_XDECREF(ste);
+ return NULL;
+}
+
+static PyObject *
+ste_repr(PySTEntryObject *ste)
+{
+ char buf[256];
+
+ PyOS_snprintf(buf, sizeof(buf),
+ "<symtable entry %.100s(%ld), line %d>",
+ PyString_AS_STRING(ste->ste_name),
+ PyInt_AS_LONG(ste->ste_id), ste->ste_lineno);
+ return PyString_FromString(buf);
+}
+
+static void
+ste_dealloc(PySTEntryObject *ste)
+{
+ ste->ste_table = NULL;
+ Py_XDECREF(ste->ste_id);
+ Py_XDECREF(ste->ste_name);
+ Py_XDECREF(ste->ste_symbols);
+ Py_XDECREF(ste->ste_varnames);
+ Py_XDECREF(ste->ste_children);
+ PyObject_Del(ste);
+}
+
+#define OFF(x) offsetof(PySTEntryObject, x)
+
+static PyMemberDef ste_memberlist[] = {
+ {"id", T_OBJECT, OFF(ste_id), READONLY},
+ {"name", T_OBJECT, OFF(ste_name), READONLY},
+ {"symbols", T_OBJECT, OFF(ste_symbols), READONLY},
+ {"varnames", T_OBJECT, OFF(ste_varnames), READONLY},
+ {"children", T_OBJECT, OFF(ste_children), READONLY},
+ {"optimized",T_INT, OFF(ste_unoptimized), READONLY},
+ {"nested", T_INT, OFF(ste_nested), READONLY},
+ {"type", T_INT, OFF(ste_type), READONLY},
+ {"lineno", T_INT, OFF(ste_lineno), READONLY},
+ {NULL}
+};
+
+PyTypeObject PySTEntry_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "symtable entry",
+ sizeof(PySTEntryObject),
+ 0,
+ (destructor)ste_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)ste_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ ste_memberlist, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static int symtable_analyze(struct symtable *st);
+static int symtable_warn(struct symtable *st,
+ PyObject *warn, const char *msg, int lineno);
+static int symtable_enter_block(struct symtable *st, identifier name,
+ _Py_block_ty block, void *ast, int lineno);
+static int symtable_exit_block(struct symtable *st, void *ast);
+static int symtable_visit_stmt(struct symtable *st, stmt_ty s);
+static int symtable_visit_expr(struct symtable *st, expr_ty s);
+static int symtable_visit_listcomp(struct symtable *st, expr_ty e);
+static int symtable_visit_genexp(struct symtable *st, expr_ty s);
+static int symtable_visit_setcomp(struct symtable *st, expr_ty e);
+static int symtable_visit_dictcomp(struct symtable *st, expr_ty e);
+static int symtable_visit_arguments(struct symtable *st, arguments_ty);
+static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty);
+static int symtable_visit_alias(struct symtable *st, alias_ty);
+static int symtable_visit_comprehension(struct symtable *st, comprehension_ty);
+static int symtable_visit_keyword(struct symtable *st, keyword_ty);
+static int symtable_visit_slice(struct symtable *st, slice_ty);
+static int symtable_visit_params(struct symtable *st, asdl_seq *args, int top);
+static int symtable_visit_params_nested(struct symtable *st, asdl_seq *args);
+static int symtable_implicit_arg(struct symtable *st, int pos);
+
+
+static identifier top = NULL, lambda = NULL, genexpr = NULL, setcomp = NULL,
+ dictcomp = NULL;
+
+#define GET_IDENTIFIER(VAR) \
+ ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR)))
+
+#define DUPLICATE_ARGUMENT \
+"duplicate argument '%s' in function definition"
+
+static struct symtable *
+symtable_new(void)
+{
+ struct symtable *st;
+
+ st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
+ if (st == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ st->st_filename = NULL;
+ st->st_symbols = NULL;
+
+ if ((st->st_stack = PyList_New(0)) == NULL)
+ goto fail;
+ if ((st->st_symbols = PyDict_New()) == NULL)
+ goto fail;
+ st->st_cur = NULL;
+ st->st_private = NULL;
+ return st;
+ fail:
+ PySymtable_Free(st);
+ return NULL;
+}
+
+struct symtable *
+PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
+{
+ struct symtable *st = symtable_new();
+ asdl_seq *seq;
+ int i;
+
+ if (st == NULL)
+ return st;
+ st->st_filename = filename;
+ st->st_future = future;
+ if (!GET_IDENTIFIER(top) ||
+ !symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0)) {
+ PySymtable_Free(st);
+ return NULL;
+ }
+
+ st->st_top = st->st_cur;
+ st->st_cur->ste_unoptimized = OPT_TOPLEVEL;
+ /* Any other top-level initialization? */
+ switch (mod->kind) {
+ case Module_kind:
+ seq = mod->v.Module.body;
+ for (i = 0; i < asdl_seq_LEN(seq); i++)
+ if (!symtable_visit_stmt(st,
+ (stmt_ty)asdl_seq_GET(seq, i)))
+ goto error;
+ break;
+ case Expression_kind:
+ if (!symtable_visit_expr(st, mod->v.Expression.body))
+ goto error;
+ break;
+ case Interactive_kind:
+ seq = mod->v.Interactive.body;
+ for (i = 0; i < asdl_seq_LEN(seq); i++)
+ if (!symtable_visit_stmt(st,
+ (stmt_ty)asdl_seq_GET(seq, i)))
+ goto error;
+ break;
+ case Suite_kind:
+ PyErr_SetString(PyExc_RuntimeError,
+ "this compiler does not handle Suites");
+ goto error;
+ }
+ if (!symtable_exit_block(st, (void *)mod)) {
+ PySymtable_Free(st);
+ return NULL;
+ }
+ if (symtable_analyze(st))
+ return st;
+ PySymtable_Free(st);
+ return NULL;
+ error:
+ (void) symtable_exit_block(st, (void *)mod);
+ PySymtable_Free(st);
+ return NULL;
+}
+
+void
+PySymtable_Free(struct symtable *st)
+{
+ Py_XDECREF(st->st_symbols);
+ Py_XDECREF(st->st_stack);
+ PyMem_Free((void *)st);
+}
+
+PySTEntryObject *
+PySymtable_Lookup(struct symtable *st, void *key)
+{
+ PyObject *k, *v;
+
+ k = PyLong_FromVoidPtr(key);
+ if (k == NULL)
+ return NULL;
+ v = PyDict_GetItem(st->st_symbols, k);
+ if (v) {
+ assert(PySTEntry_Check(v));
+ Py_INCREF(v);
+ }
+ else {
+ PyErr_SetString(PyExc_KeyError,
+ "unknown symbol table entry");
+ }
+
+ Py_DECREF(k);
+ return (PySTEntryObject *)v;
+}
+
+int
+PyST_GetScope(PySTEntryObject *ste, PyObject *name)
+{
+ PyObject *v = PyDict_GetItem(ste->ste_symbols, name);
+ if (!v)
+ return 0;
+ assert(PyInt_Check(v));
+ return (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK;
+}
+
+
+/* Analyze raw symbol information to determine scope of each name.
+
+ The next several functions are helpers for PySymtable_Analyze(),
+ which determines whether a name is local, global, or free. In addition,
+ it determines which local variables are cell variables; they provide
+ bindings that are used for free variables in enclosed blocks.
+
+ There are also two kinds of free variables, implicit and explicit. An
+ explicit global is declared with the global statement. An implicit
+ global is a free variable for which the compiler has found no binding
+ in an enclosing function scope. The implicit global is either a global
+ or a builtin. Python's module and class blocks use the xxx_NAME opcodes
+ to handle these names to implement slightly odd semantics. In such a
+ block, the name is treated as global until it is assigned to; then it
+ is treated as a local.
+
+ The symbol table requires two passes to determine the scope of each name.
+ The first pass collects raw facts from the AST: the name is a parameter
+ here, the name is used by not defined here, etc. The second pass analyzes
+ these facts during a pass over the PySTEntryObjects created during pass 1.
+
+ When a function is entered during the second pass, the parent passes
+ the set of all name bindings visible to its children. These bindings
+ are used to determine if the variable is free or an implicit global.
+ After doing the local analysis, it analyzes each of its child blocks
+ using an updated set of name bindings.
+
+ The children update the free variable set. If a local variable is free
+ in a child, the variable is marked as a cell. The current function must
+ provide runtime storage for the variable that may outlive the function's
+ frame. Cell variables are removed from the free set before the analyze
+ function returns to its parent.
+
+ The sets of bound and free variables are implemented as dictionaries
+ mapping strings to None.
+*/
+
+#define SET_SCOPE(DICT, NAME, I) { \
+ PyObject *o = PyInt_FromLong(I); \
+ if (!o) \
+ return 0; \
+ if (PyDict_SetItem((DICT), (NAME), o) < 0) { \
+ Py_DECREF(o); \
+ return 0; \
+ } \
+ Py_DECREF(o); \
+}
+
+/* Decide on scope of name, given flags.
+
+ The namespace dictionaries may be modified to record information
+ about the new name. For example, a new global will add an entry to
+ global. A name that was global can be changed to local.
+*/
+
+static int
+analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags,
+ PyObject *bound, PyObject *local, PyObject *free,
+ PyObject *global)
+{
+ if (flags & DEF_GLOBAL) {
+ if (flags & DEF_PARAM) {
+ PyErr_Format(PyExc_SyntaxError,
+ "name '%s' is local and global",
+ PyString_AS_STRING(name));
+ PyErr_SyntaxLocation(ste->ste_table->st_filename,
+ ste->ste_lineno);
+
+ return 0;
+ }
+ SET_SCOPE(dict, name, GLOBAL_EXPLICIT);
+ if (PyDict_SetItem(global, name, Py_None) < 0)
+ return 0;
+ if (bound && PyDict_GetItem(bound, name)) {
+ if (PyDict_DelItem(bound, name) < 0)
+ return 0;
+ }
+ return 1;
+ }
+ if (flags & DEF_BOUND) {
+ SET_SCOPE(dict, name, LOCAL);
+ if (PyDict_SetItem(local, name, Py_None) < 0)
+ return 0;
+ if (PyDict_GetItem(global, name)) {
+ if (PyDict_DelItem(global, name) < 0)
+ return 0;
+ }
+ return 1;
+ }
+ /* If an enclosing block has a binding for this name, it
+ is a free variable rather than a global variable.
+ Note that having a non-NULL bound implies that the block
+ is nested.
+ */
+ if (bound && PyDict_GetItem(bound, name)) {
+ SET_SCOPE(dict, name, FREE);
+ ste->ste_free = 1;
+ if (PyDict_SetItem(free, name, Py_None) < 0)
+ return 0;
+ return 1;
+ }
+ /* If a parent has a global statement, then call it global
+ explicit? It could also be global implicit.
+ */
+ else if (global && PyDict_GetItem(global, name)) {
+ SET_SCOPE(dict, name, GLOBAL_IMPLICIT);
+ return 1;
+ }
+ else {
+ if (ste->ste_nested)
+ ste->ste_free = 1;
+ SET_SCOPE(dict, name, GLOBAL_IMPLICIT);
+ return 1;
+ }
+ /* Should never get here. */
+ PyErr_Format(PyExc_SystemError, "failed to set scope for %s",
+ PyString_AS_STRING(name));
+ return 0;
+}
+
+#undef SET_SCOPE
+
+/* If a name is defined in free and also in locals, then this block
+ provides the binding for the free variable. The name should be
+ marked CELL in this block and removed from the free list.
+
+ Note that the current block's free variables are included in free.
+ That's safe because no name can be free and local in the same scope.
+*/
+
+static int
+analyze_cells(PyObject *scope, PyObject *free)
+{
+ PyObject *name, *v, *w;
+ int success = 0;
+ Py_ssize_t pos = 0;
+
+ w = PyInt_FromLong(CELL);
+ if (!w)
+ return 0;
+ while (PyDict_Next(scope, &pos, &name, &v)) {
+ long flags;
+ assert(PyInt_Check(v));
+ flags = PyInt_AS_LONG(v);
+ if (flags != LOCAL)
+ continue;
+ if (!PyDict_GetItem(free, name))
+ continue;
+ /* Replace LOCAL with CELL for this name, and remove
+ from free. It is safe to replace the value of name
+ in the dict, because it will not cause a resize.
+ */
+ if (PyDict_SetItem(scope, name, w) < 0)
+ goto error;
+ if (PyDict_DelItem(free, name) < 0)
+ goto error;
+ }
+ success = 1;
+ error:
+ Py_DECREF(w);
+ return success;
+}
+
+/* Check for illegal statements in unoptimized namespaces */
+static int
+check_unoptimized(const PySTEntryObject* ste) {
+ char buf[300];
+ const char* trailer;
+
+ if (ste->ste_type != FunctionBlock || !ste->ste_unoptimized
+ || !(ste->ste_free || ste->ste_child_free))
+ return 1;
+
+ trailer = (ste->ste_child_free ?
+ "contains a nested function with free variables" :
+ "is a nested function");
+
+ switch (ste->ste_unoptimized) {
+ case OPT_TOPLEVEL: /* exec / import * at top-level is fine */
+ case OPT_EXEC: /* qualified exec is fine */
+ return 1;
+ case OPT_IMPORT_STAR:
+ PyOS_snprintf(buf, sizeof(buf),
+ "import * is not allowed in function '%.100s' "
+ "because it %s",
+ PyString_AS_STRING(ste->ste_name), trailer);
+ break;
+ case OPT_BARE_EXEC:
+ PyOS_snprintf(buf, sizeof(buf),
+ "unqualified exec is not allowed in function "
+ "'%.100s' because it %s",
+ PyString_AS_STRING(ste->ste_name), trailer);
+ break;
+ default:
+ PyOS_snprintf(buf, sizeof(buf),
+ "function '%.100s' uses import * and bare exec, "
+ "which are illegal because it %s",
+ PyString_AS_STRING(ste->ste_name), trailer);
+ break;
+ }
+
+ PyErr_SetString(PyExc_SyntaxError, buf);
+ PyErr_SyntaxLocation(ste->ste_table->st_filename,
+ ste->ste_opt_lineno);
+ return 0;
+}
+
+/* Enter the final scope information into the st_symbols dict.
+ *
+ * All arguments are dicts. Modifies symbols, others are read-only.
+*/
+static int
+update_symbols(PyObject *symbols, PyObject *scope,
+ PyObject *bound, PyObject *free, int classflag)
+{
+ PyObject *name, *v, *u, *w, *free_value = NULL;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(symbols, &pos, &name, &v)) {
+ long i, flags;
+ assert(PyInt_Check(v));
+ flags = PyInt_AS_LONG(v);
+ w = PyDict_GetItem(scope, name);
+ assert(w && PyInt_Check(w));
+ i = PyInt_AS_LONG(w);
+ flags |= (i << SCOPE_OFF);
+ u = PyInt_FromLong(flags);
+ if (!u)
+ return 0;
+ if (PyDict_SetItem(symbols, name, u) < 0) {
+ Py_DECREF(u);
+ return 0;
+ }
+ Py_DECREF(u);
+ }
+
+ free_value = PyInt_FromLong(FREE << SCOPE_OFF);
+ if (!free_value)
+ return 0;
+
+ /* add a free variable when it's only use is for creating a closure */
+ pos = 0;
+ while (PyDict_Next(free, &pos, &name, &v)) {
+ PyObject *o = PyDict_GetItem(symbols, name);
+
+ if (o) {
+ /* It could be a free variable in a method of
+ the class that has the same name as a local
+ or global in the class scope.
+ */
+ if (classflag &&
+ PyInt_AS_LONG(o) & (DEF_BOUND | DEF_GLOBAL)) {
+ long i = PyInt_AS_LONG(o) | DEF_FREE_CLASS;
+ o = PyInt_FromLong(i);
+ if (!o) {
+ Py_DECREF(free_value);
+ return 0;
+ }
+ if (PyDict_SetItem(symbols, name, o) < 0) {
+ Py_DECREF(o);
+ Py_DECREF(free_value);
+ return 0;
+ }
+ Py_DECREF(o);
+ }
+ /* else it's not free, probably a cell */
+ continue;
+ }
+ if (!PyDict_GetItem(bound, name))
+ continue; /* it's a global */
+
+ if (PyDict_SetItem(symbols, name, free_value) < 0) {
+ Py_DECREF(free_value);
+ return 0;
+ }
+ }
+ Py_DECREF(free_value);
+ return 1;
+}
+
+/* Make final symbol table decisions for block of ste.
+
+ Arguments:
+ ste -- current symtable entry (input/output)
+ bound -- set of variables bound in enclosing scopes (input). bound
+ is NULL for module blocks.
+ free -- set of free variables in enclosed scopes (output)
+ globals -- set of declared global variables in enclosing scopes (input)
+
+ The implementation uses two mutually recursive functions,
+ analyze_block() and analyze_child_block(). analyze_block() is
+ responsible for analyzing the individual names defined in a block.
+ analyze_child_block() prepares temporary namespace dictionaries
+ used to evaluated nested blocks.
+
+ The two functions exist because a child block should see the name
+ bindings of its enclosing blocks, but those bindings should not
+ propagate back to a parent block.
+*/
+
+static int
+analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
+ PyObject *global, PyObject* child_free);
+
+static int
+analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
+ PyObject *global)
+{
+ PyObject *name, *v, *local = NULL, *scope = NULL;
+ PyObject *newbound = NULL, *newglobal = NULL;
+ PyObject *newfree = NULL, *allfree = NULL;
+ int i, success = 0;
+ Py_ssize_t pos = 0;
+
+ local = PyDict_New(); /* collect new names bound in block */
+ if (!local)
+ goto error;
+ scope = PyDict_New(); /* collect scopes defined for each name */
+ if (!scope)
+ goto error;
+
+ /* Allocate new global and bound variable dictionaries. These
+ dictionaries hold the names visible in nested blocks. For
+ ClassBlocks, the bound and global names are initialized
+ before analyzing names, because class bindings aren't
+ visible in methods. For other blocks, they are initialized
+ after names are analyzed.
+ */
+
+ /* TODO(jhylton): Package these dicts in a struct so that we
+ can write reasonable helper functions?
+ */
+ newglobal = PyDict_New();
+ if (!newglobal)
+ goto error;
+ newbound = PyDict_New();
+ if (!newbound)
+ goto error;
+ newfree = PyDict_New();
+ if (!newfree)
+ goto error;
+
+ if (ste->ste_type == ClassBlock) {
+ if (PyDict_Update(newglobal, global) < 0)
+ goto error;
+ if (bound)
+ if (PyDict_Update(newbound, bound) < 0)
+ goto error;
+ }
+
+ while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
+ long flags = PyInt_AS_LONG(v);
+ if (!analyze_name(ste, scope, name, flags,
+ bound, local, free, global))
+ goto error;
+ }
+
+ if (ste->ste_type != ClassBlock) {
+ if (ste->ste_type == FunctionBlock) {
+ if (PyDict_Update(newbound, local) < 0)
+ goto error;
+ }
+ if (bound) {
+ if (PyDict_Update(newbound, bound) < 0)
+ goto error;
+ }
+ if (PyDict_Update(newglobal, global) < 0)
+ goto error;
+ }
+
+ /* Recursively call analyze_block() on each child block.
+
+ newbound, newglobal now contain the names visible in
+ nested blocks. The free variables in the children will
+ be collected in allfree.
+ */
+ allfree = PyDict_New();
+ if (!allfree)
+ goto error;
+ for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
+ PyObject *c = PyList_GET_ITEM(ste->ste_children, i);
+ PySTEntryObject* entry;
+ assert(c && PySTEntry_Check(c));
+ entry = (PySTEntryObject*)c;
+ if (!analyze_child_block(entry, newbound, newfree, newglobal,
+ allfree))
+ goto error;
+ if (entry->ste_free || entry->ste_child_free)
+ ste->ste_child_free = 1;
+ }
+
+ if (PyDict_Update(newfree, allfree) < 0)
+ goto error;
+ if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree))
+ goto error;
+ if (!update_symbols(ste->ste_symbols, scope, bound, newfree,
+ ste->ste_type == ClassBlock))
+ goto error;
+ if (!check_unoptimized(ste))
+ goto error;
+
+ if (PyDict_Update(free, newfree) < 0)
+ goto error;
+ success = 1;
+ error:
+ Py_XDECREF(local);
+ Py_XDECREF(scope);
+ Py_XDECREF(newbound);
+ Py_XDECREF(newglobal);
+ Py_XDECREF(newfree);
+ Py_XDECREF(allfree);
+ if (!success)
+ assert(PyErr_Occurred());
+ return success;
+}
+
+static int
+analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
+ PyObject *global, PyObject* child_free)
+{
+ PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL;
+
+ /* Copy the bound and global dictionaries.
+
+ These dictionaries are used by all blocks enclosed by the
+ current block. The analyze_block() call modifies these
+ dictionaries.
+
+ */
+ temp_bound = PyDict_New();
+ if (!temp_bound)
+ goto error;
+ if (PyDict_Update(temp_bound, bound) < 0)
+ goto error;
+ temp_free = PyDict_New();
+ if (!temp_free)
+ goto error;
+ if (PyDict_Update(temp_free, free) < 0)
+ goto error;
+ temp_global = PyDict_New();
+ if (!temp_global)
+ goto error;
+ if (PyDict_Update(temp_global, global) < 0)
+ goto error;
+
+ if (!analyze_block(entry, temp_bound, temp_free, temp_global))
+ goto error;
+ if (PyDict_Update(child_free, temp_free) < 0)
+ goto error;
+ Py_DECREF(temp_bound);
+ Py_DECREF(temp_free);
+ Py_DECREF(temp_global);
+ return 1;
+ error:
+ Py_XDECREF(temp_bound);
+ Py_XDECREF(temp_free);
+ Py_XDECREF(temp_global);
+ return 0;
+}
+
+static int
+symtable_analyze(struct symtable *st)
+{
+ PyObject *free, *global;
+ int r;
+
+ free = PyDict_New();
+ if (!free)
+ return 0;
+ global = PyDict_New();
+ if (!global) {
+ Py_DECREF(free);
+ return 0;
+ }
+ r = analyze_block(st->st_top, NULL, free, global);
+ Py_DECREF(free);
+ Py_DECREF(global);
+ return r;
+}
+
+
+static int
+symtable_warn(struct symtable *st, PyObject *warn, const char *msg, int lineno)
+{
+ if (lineno < 0) {
+ lineno = st->st_cur->ste_lineno;
+ }
+ if (PyErr_WarnExplicit(warn, msg, st->st_filename, lineno, NULL, NULL) < 0) {
+ if (PyErr_ExceptionMatches(warn)) {
+ /* Replace the warning exception with a SyntaxError
+ to get a more accurate error report */
+ PyErr_Clear();
+ PyErr_SetString(PyExc_SyntaxError, msg);
+ PyErr_SyntaxLocation(st->st_filename, lineno);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/* symtable_enter_block() gets a reference via ste_new.
+ This reference is released when the block is exited, via the DECREF
+ in symtable_exit_block().
+*/
+
+static int
+symtable_exit_block(struct symtable *st, void *ast)
+{
+ Py_ssize_t end;
+
+ Py_CLEAR(st->st_cur);
+ end = PyList_GET_SIZE(st->st_stack) - 1;
+ if (end >= 0) {
+ st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack,
+ end);
+ if (st->st_cur == NULL)
+ return 0;
+ Py_INCREF(st->st_cur);
+ if (PySequence_DelItem(st->st_stack, end) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+static int
+symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
+ void *ast, int lineno)
+{
+ PySTEntryObject *prev = NULL;
+
+ if (st->st_cur) {
+ prev = st->st_cur;
+ if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
+ return 0;
+ }
+ Py_DECREF(st->st_cur);
+ }
+ st->st_cur = ste_new(st, name, block, ast, lineno);
+ if (st->st_cur == NULL)
+ return 0;
+ if (block == ModuleBlock)
+ st->st_global = st->st_cur->ste_symbols;
+ if (prev) {
+ if (PyList_Append(prev->ste_children,
+ (PyObject *)st->st_cur) < 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static long
+symtable_lookup(struct symtable *st, PyObject *name)
+{
+ PyObject *o;
+ PyObject *mangled = _Py_Mangle(st->st_private, name);
+ if (!mangled)
+ return 0;
+ o = PyDict_GetItem(st->st_cur->ste_symbols, mangled);
+ Py_DECREF(mangled);
+ if (!o)
+ return 0;
+ return PyInt_AsLong(o);
+}
+
+static int
+symtable_add_def(struct symtable *st, PyObject *name, int flag)
+{
+ PyObject *o;
+ PyObject *dict;
+ long val;
+ PyObject *mangled = _Py_Mangle(st->st_private, name);
+
+ if (!mangled)
+ return 0;
+ dict = st->st_cur->ste_symbols;
+ if ((o = PyDict_GetItem(dict, mangled))) {
+ val = PyInt_AS_LONG(o);
+ if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
+ /* Is it better to use 'mangled' or 'name' here? */
+ PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
+ PyString_AsString(name));
+ PyErr_SyntaxLocation(st->st_filename,
+ st->st_cur->ste_lineno);
+ goto error;
+ }
+ val |= flag;
+ } else
+ val = flag;
+ o = PyInt_FromLong(val);
+ if (o == NULL)
+ goto error;
+ if (PyDict_SetItem(dict, mangled, o) < 0) {
+ Py_DECREF(o);
+ goto error;
+ }
+ Py_DECREF(o);
+
+ if (flag & DEF_PARAM) {
+ if (PyList_Append(st->st_cur->ste_varnames, mangled) < 0)
+ goto error;
+ } else if (flag & DEF_GLOBAL) {
+ /* XXX need to update DEF_GLOBAL for other flags too;
+ perhaps only DEF_FREE_GLOBAL */
+ val = flag;
+ if ((o = PyDict_GetItem(st->st_global, mangled))) {
+ val |= PyInt_AS_LONG(o);
+ }
+ o = PyInt_FromLong(val);
+ if (o == NULL)
+ goto error;
+ if (PyDict_SetItem(st->st_global, mangled, o) < 0) {
+ Py_DECREF(o);
+ goto error;
+ }
+ Py_DECREF(o);
+ }
+ Py_DECREF(mangled);
+ return 1;
+
+error:
+ Py_DECREF(mangled);
+ return 0;
+}
+
+/* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument.
+ They use the ASDL name to synthesize the name of the C type and the visit
+ function.
+
+ VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is
+ useful if the first node in the sequence requires special treatment.
+*/
+
+#define VISIT(ST, TYPE, V) \
+ if (!symtable_visit_ ## TYPE((ST), (V))) \
+ return 0;
+
+#define VISIT_IN_BLOCK(ST, TYPE, V, S) \
+ if (!symtable_visit_ ## TYPE((ST), (V))) { \
+ symtable_exit_block((ST), (S)); \
+ return 0; \
+ }
+
+#define VISIT_SEQ(ST, TYPE, SEQ) { \
+ int i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (i = 0; i < asdl_seq_LEN(seq); i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
+ if (!symtable_visit_ ## TYPE((ST), elt)) \
+ return 0; \
+ } \
+}
+
+#define VISIT_SEQ_IN_BLOCK(ST, TYPE, SEQ, S) { \
+ int i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (i = 0; i < asdl_seq_LEN(seq); i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
+ if (!symtable_visit_ ## TYPE((ST), elt)) { \
+ symtable_exit_block((ST), (S)); \
+ return 0; \
+ } \
+ } \
+}
+
+#define VISIT_SEQ_TAIL(ST, TYPE, SEQ, START) { \
+ int i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (i = (START); i < asdl_seq_LEN(seq); i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
+ if (!symtable_visit_ ## TYPE((ST), elt)) \
+ return 0; \
+ } \
+}
+
+#define VISIT_SEQ_TAIL_IN_BLOCK(ST, TYPE, SEQ, START, S) { \
+ int i; \
+ asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+ for (i = (START); i < asdl_seq_LEN(seq); i++) { \
+ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
+ if (!symtable_visit_ ## TYPE((ST), elt)) { \
+ symtable_exit_block((ST), (S)); \
+ return 0; \
+ } \
+ } \
+}
+
+static int
+symtable_visit_stmt(struct symtable *st, stmt_ty s)
+{
+ switch (s->kind) {
+ case FunctionDef_kind:
+ if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL))
+ return 0;
+ if (s->v.FunctionDef.args->defaults)
+ VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
+ if (s->v.FunctionDef.decorator_list)
+ VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
+ if (!symtable_enter_block(st, s->v.FunctionDef.name,
+ FunctionBlock, (void *)s, s->lineno))
+ return 0;
+ VISIT_IN_BLOCK(st, arguments, s->v.FunctionDef.args, s);
+ VISIT_SEQ_IN_BLOCK(st, stmt, s->v.FunctionDef.body, s);
+ if (!symtable_exit_block(st, s))
+ return 0;
+ break;
+ case ClassDef_kind: {
+ PyObject *tmp;
+ if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL))
+ return 0;
+ VISIT_SEQ(st, expr, s->v.ClassDef.bases);
+ if (s->v.ClassDef.decorator_list)
+ VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list);
+ if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
+ (void *)s, s->lineno))
+ return 0;
+ tmp = st->st_private;
+ st->st_private = s->v.ClassDef.name;
+ VISIT_SEQ_IN_BLOCK(st, stmt, s->v.ClassDef.body, s);
+ st->st_private = tmp;
+ if (!symtable_exit_block(st, s))
+ return 0;
+ break;
+ }
+ case Return_kind:
+ if (s->v.Return.value) {
+ VISIT(st, expr, s->v.Return.value);
+ st->st_cur->ste_returns_value = 1;
+ if (st->st_cur->ste_generator) {
+ PyErr_SetString(PyExc_SyntaxError,
+ RETURN_VAL_IN_GENERATOR);
+ PyErr_SyntaxLocation(st->st_filename,
+ s->lineno);
+ return 0;
+ }
+ }
+ break;
+ case Delete_kind:
+ VISIT_SEQ(st, expr, s->v.Delete.targets);
+ break;
+ case Assign_kind:
+ VISIT_SEQ(st, expr, s->v.Assign.targets);
+ VISIT(st, expr, s->v.Assign.value);
+ break;
+ case AugAssign_kind:
+ VISIT(st, expr, s->v.AugAssign.target);
+ VISIT(st, expr, s->v.AugAssign.value);
+ break;
+ case Print_kind:
+ if (s->v.Print.dest)
+ VISIT(st, expr, s->v.Print.dest);
+ VISIT_SEQ(st, expr, s->v.Print.values);
+ break;
+ case For_kind:
+ VISIT(st, expr, s->v.For.target);
+ VISIT(st, expr, s->v.For.iter);
+ VISIT_SEQ(st, stmt, s->v.For.body);
+ if (s->v.For.orelse)
+ VISIT_SEQ(st, stmt, s->v.For.orelse);
+ break;
+ case While_kind:
+ VISIT(st, expr, s->v.While.test);
+ VISIT_SEQ(st, stmt, s->v.While.body);
+ if (s->v.While.orelse)
+ VISIT_SEQ(st, stmt, s->v.While.orelse);
+ break;
+ case If_kind:
+ /* XXX if 0: and lookup_yield() hacks */
+ VISIT(st, expr, s->v.If.test);
+ VISIT_SEQ(st, stmt, s->v.If.body);
+ if (s->v.If.orelse)
+ VISIT_SEQ(st, stmt, s->v.If.orelse);
+ break;
+ case Raise_kind:
+ if (s->v.Raise.type) {
+ VISIT(st, expr, s->v.Raise.type);
+ if (s->v.Raise.inst) {
+ VISIT(st, expr, s->v.Raise.inst);
+ if (s->v.Raise.tback)
+ VISIT(st, expr, s->v.Raise.tback);
+ }
+ }
+ break;
+ case TryExcept_kind:
+ VISIT_SEQ(st, stmt, s->v.TryExcept.body);
+ VISIT_SEQ(st, stmt, s->v.TryExcept.orelse);
+ VISIT_SEQ(st, excepthandler, s->v.TryExcept.handlers);
+ break;
+ case TryFinally_kind:
+ VISIT_SEQ(st, stmt, s->v.TryFinally.body);
+ VISIT_SEQ(st, stmt, s->v.TryFinally.finalbody);
+ break;
+ case Assert_kind:
+ VISIT(st, expr, s->v.Assert.test);
+ if (s->v.Assert.msg)
+ VISIT(st, expr, s->v.Assert.msg);
+ break;
+ case Import_kind:
+ VISIT_SEQ(st, alias, s->v.Import.names);
+ /* XXX Don't have the lineno available inside
+ visit_alias */
+ if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno)
+ st->st_cur->ste_opt_lineno = s->lineno;
+ break;
+ case ImportFrom_kind:
+ VISIT_SEQ(st, alias, s->v.ImportFrom.names);
+ /* XXX Don't have the lineno available inside
+ visit_alias */
+ if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno)
+ st->st_cur->ste_opt_lineno = s->lineno;
+ break;
+ case Exec_kind:
+ VISIT(st, expr, s->v.Exec.body);
+ if (!st->st_cur->ste_opt_lineno)
+ st->st_cur->ste_opt_lineno = s->lineno;
+ if (s->v.Exec.globals) {
+ st->st_cur->ste_unoptimized |= OPT_EXEC;
+ VISIT(st, expr, s->v.Exec.globals);
+ if (s->v.Exec.locals)
+ VISIT(st, expr, s->v.Exec.locals);
+ } else {
+ st->st_cur->ste_unoptimized |= OPT_BARE_EXEC;
+ }
+ break;
+ case Global_kind: {
+ int i;
+ asdl_seq *seq = s->v.Global.names;
+ for (i = 0; i < asdl_seq_LEN(seq); i++) {
+ identifier name = (identifier)asdl_seq_GET(seq, i);
+ char *c_name = PyString_AS_STRING(name);
+ long cur = symtable_lookup(st, name);
+ if (cur < 0)
+ return 0;
+ if (cur & (DEF_LOCAL | USE)) {
+ char buf[256];
+ if (cur & DEF_LOCAL)
+ PyOS_snprintf(buf, sizeof(buf),
+ GLOBAL_AFTER_ASSIGN,
+ c_name);
+ else
+ PyOS_snprintf(buf, sizeof(buf),
+ GLOBAL_AFTER_USE,
+ c_name);
+ if (!symtable_warn(st, PyExc_SyntaxWarning, buf, s->lineno))
+ return 0;
+ }
+ if (!symtable_add_def(st, name, DEF_GLOBAL))
+ return 0;
+ }
+ break;
+ }
+ case Expr_kind:
+ VISIT(st, expr, s->v.Expr.value);
+ break;
+ case Pass_kind:
+ case Break_kind:
+ case Continue_kind:
+ /* nothing to do here */
+ break;
+ case With_kind:
+ VISIT(st, expr, s->v.With.context_expr);
+ if (s->v.With.optional_vars) {
+ VISIT(st, expr, s->v.With.optional_vars);
+ }
+ VISIT_SEQ(st, stmt, s->v.With.body);
+ break;
+ }
+ return 1;
+}
+
+static int
+symtable_visit_expr(struct symtable *st, expr_ty e)
+{
+ switch (e->kind) {
+ case BoolOp_kind:
+ VISIT_SEQ(st, expr, e->v.BoolOp.values);
+ break;
+ case BinOp_kind:
+ VISIT(st, expr, e->v.BinOp.left);
+ VISIT(st, expr, e->v.BinOp.right);
+ break;
+ case UnaryOp_kind:
+ VISIT(st, expr, e->v.UnaryOp.operand);
+ break;
+ case Lambda_kind: {
+ if (!GET_IDENTIFIER(lambda))
+ return 0;
+ if (e->v.Lambda.args->defaults)
+ VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
+ if (!symtable_enter_block(st, lambda,
+ FunctionBlock, (void *)e, e->lineno))
+ return 0;
+ VISIT_IN_BLOCK(st, arguments, e->v.Lambda.args, (void*)e);
+ VISIT_IN_BLOCK(st, expr, e->v.Lambda.body, (void*)e);
+ if (!symtable_exit_block(st, (void *)e))
+ return 0;
+ break;
+ }
+ case IfExp_kind:
+ VISIT(st, expr, e->v.IfExp.test);
+ VISIT(st, expr, e->v.IfExp.body);
+ VISIT(st, expr, e->v.IfExp.orelse);
+ break;
+ case Dict_kind:
+ VISIT_SEQ(st, expr, e->v.Dict.keys);
+ VISIT_SEQ(st, expr, e->v.Dict.values);
+ break;
+ case Set_kind:
+ VISIT_SEQ(st, expr, e->v.Set.elts);
+ break;
+ case ListComp_kind:
+ if (!symtable_visit_listcomp(st, e))
+ return 0;
+ break;
+ case GeneratorExp_kind:
+ if (!symtable_visit_genexp(st, e))
+ return 0;
+ break;
+ case SetComp_kind:
+ if (!symtable_visit_setcomp(st, e))
+ return 0;
+ break;
+ case DictComp_kind:
+ if (!symtable_visit_dictcomp(st, e))
+ return 0;
+ break;
+ case Yield_kind:
+ if (e->v.Yield.value)
+ VISIT(st, expr, e->v.Yield.value);
+ st->st_cur->ste_generator = 1;
+ if (st->st_cur->ste_returns_value) {
+ PyErr_SetString(PyExc_SyntaxError,
+ RETURN_VAL_IN_GENERATOR);
+ PyErr_SyntaxLocation(st->st_filename,
+ e->lineno);
+ return 0;
+ }
+ break;
+ case Compare_kind:
+ VISIT(st, expr, e->v.Compare.left);
+ VISIT_SEQ(st, expr, e->v.Compare.comparators);
+ break;
+ case Call_kind:
+ VISIT(st, expr, e->v.Call.func);
+ VISIT_SEQ(st, expr, e->v.Call.args);
+ VISIT_SEQ(st, keyword, e->v.Call.keywords);
+ if (e->v.Call.starargs)
+ VISIT(st, expr, e->v.Call.starargs);
+ if (e->v.Call.kwargs)
+ VISIT(st, expr, e->v.Call.kwargs);
+ break;
+ case Repr_kind:
+ VISIT(st, expr, e->v.Repr.value);
+ break;
+ case Num_kind:
+ case Str_kind:
+ /* Nothing to do here. */
+ break;
+ /* The following exprs can be assignment targets. */
+ case Attribute_kind:
+ VISIT(st, expr, e->v.Attribute.value);
+ break;
+ case Subscript_kind:
+ VISIT(st, expr, e->v.Subscript.value);
+ VISIT(st, slice, e->v.Subscript.slice);
+ break;
+ case Name_kind:
+ if (!symtable_add_def(st, e->v.Name.id,
+ e->v.Name.ctx == Load ? USE : DEF_LOCAL))
+ return 0;
+ break;
+ /* child nodes of List and Tuple will have expr_context set */
+ case List_kind:
+ VISIT_SEQ(st, expr, e->v.List.elts);
+ break;
+ case Tuple_kind:
+ VISIT_SEQ(st, expr, e->v.Tuple.elts);
+ break;
+ }
+ return 1;
+}
+
+static int
+symtable_implicit_arg(struct symtable *st, int pos)
+{
+ PyObject *id = PyString_FromFormat(".%d", pos);
+ if (id == NULL)
+ return 0;
+ if (!symtable_add_def(st, id, DEF_PARAM)) {
+ Py_DECREF(id);
+ return 0;
+ }
+ Py_DECREF(id);
+ return 1;
+}
+
+static int
+symtable_visit_params(struct symtable *st, asdl_seq *args, int toplevel)
+{
+ int i;
+
+ /* go through all the toplevel arguments first */
+ for (i = 0; i < asdl_seq_LEN(args); i++) {
+ expr_ty arg = (expr_ty)asdl_seq_GET(args, i);
+ if (arg->kind == Name_kind) {
+ assert(arg->v.Name.ctx == Param ||
+ (arg->v.Name.ctx == Store && !toplevel));
+ if (!symtable_add_def(st, arg->v.Name.id, DEF_PARAM))
+ return 0;
+ }
+ else if (arg->kind == Tuple_kind) {
+ assert(arg->v.Tuple.ctx == Store);
+ if (toplevel) {
+ if (!symtable_implicit_arg(st, i))
+ return 0;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_SyntaxError,
+ "invalid expression in parameter list");
+ PyErr_SyntaxLocation(st->st_filename,
+ st->st_cur->ste_lineno);
+ return 0;
+ }
+ }
+
+ if (!toplevel) {
+ if (!symtable_visit_params_nested(st, args))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+symtable_visit_params_nested(struct symtable *st, asdl_seq *args)
+{
+ int i;
+ for (i = 0; i < asdl_seq_LEN(args); i++) {
+ expr_ty arg = (expr_ty)asdl_seq_GET(args, i);
+ if (arg->kind == Tuple_kind &&
+ !symtable_visit_params(st, arg->v.Tuple.elts, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+symtable_visit_arguments(struct symtable *st, arguments_ty a)
+{
+ /* skip default arguments inside function block
+ XXX should ast be different?
+ */
+ if (a->args && !symtable_visit_params(st, a->args, 1))
+ return 0;
+ if (a->vararg) {
+ if (!symtable_add_def(st, a->vararg, DEF_PARAM))
+ return 0;
+ st->st_cur->ste_varargs = 1;
+ }
+ if (a->kwarg) {
+ if (!symtable_add_def(st, a->kwarg, DEF_PARAM))
+ return 0;
+ st->st_cur->ste_varkeywords = 1;
+ }
+ if (a->args && !symtable_visit_params_nested(st, a->args))
+ return 0;
+ return 1;
+}
+
+
+static int
+symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh)
+{
+ if (eh->v.ExceptHandler.type)
+ VISIT(st, expr, eh->v.ExceptHandler.type);
+ if (eh->v.ExceptHandler.name)
+ VISIT(st, expr, eh->v.ExceptHandler.name);
+ VISIT_SEQ(st, stmt, eh->v.ExceptHandler.body);
+ return 1;
+}
+
+
+static int
+symtable_visit_alias(struct symtable *st, alias_ty a)
+{
+ /* Compute store_name, the name actually bound by the import
+ operation. It is different than a->name when a->name is a
+ dotted package name (e.g. spam.eggs)
+ */
+ PyObject *store_name;
+ PyObject *name = (a->asname == NULL) ? a->name : a->asname;
+ const char *base = PyString_AS_STRING(name);
+ char *dot = strchr(base, '.');
+ if (dot) {
+ store_name = PyString_FromStringAndSize(base, dot - base);
+ if (!store_name)
+ return 0;
+ }
+ else {
+ store_name = name;
+ Py_INCREF(store_name);
+ }
+ if (strcmp(PyString_AS_STRING(name), "*")) {
+ int r = symtable_add_def(st, store_name, DEF_IMPORT);
+ Py_DECREF(store_name);
+ return r;
+ }
+ else {
+ if (st->st_cur->ste_type != ModuleBlock &&
+ !symtable_warn(st, PyExc_SyntaxWarning, IMPORT_STAR_WARNING, -1))
+ {
+ Py_DECREF(store_name);
+ return 0;
+ }
+ st->st_cur->ste_unoptimized |= OPT_IMPORT_STAR;
+ Py_DECREF(store_name);
+ return 1;
+ }
+}
+
+
+static int
+symtable_visit_comprehension(struct symtable *st, comprehension_ty lc)
+{
+ VISIT(st, expr, lc->target);
+ VISIT(st, expr, lc->iter);
+ VISIT_SEQ(st, expr, lc->ifs);
+ return 1;
+}
+
+
+static int
+symtable_visit_keyword(struct symtable *st, keyword_ty k)
+{
+ VISIT(st, expr, k->value);
+ return 1;
+}
+
+
+static int
+symtable_visit_slice(struct symtable *st, slice_ty s)
+{
+ switch (s->kind) {
+ case Slice_kind:
+ if (s->v.Slice.lower)
+ VISIT(st, expr, s->v.Slice.lower)
+ if (s->v.Slice.upper)
+ VISIT(st, expr, s->v.Slice.upper)
+ if (s->v.Slice.step)
+ VISIT(st, expr, s->v.Slice.step)
+ break;
+ case ExtSlice_kind:
+ VISIT_SEQ(st, slice, s->v.ExtSlice.dims)
+ break;
+ case Index_kind:
+ VISIT(st, expr, s->v.Index.value)
+ break;
+ case Ellipsis_kind:
+ break;
+ }
+ return 1;
+}
+
+static int
+symtable_new_tmpname(struct symtable *st)
+{
+ char tmpname[256];
+ identifier tmp;
+
+ PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]",
+ ++st->st_cur->ste_tmpname);
+ tmp = PyString_InternFromString(tmpname);
+ if (!tmp)
+ return 0;
+ if (!symtable_add_def(st, tmp, DEF_LOCAL))
+ return 0;
+ Py_DECREF(tmp);
+ return 1;
+}
+
+static int
+symtable_handle_comprehension(struct symtable *st, expr_ty e,
+ identifier scope_name, asdl_seq *generators,
+ expr_ty elt, expr_ty value)
+{
+ int is_generator = (e->kind == GeneratorExp_kind);
+ int needs_tmp = !is_generator;
+ comprehension_ty outermost = ((comprehension_ty)
+ asdl_seq_GET(generators, 0));
+ /* Outermost iterator is evaluated in current scope */
+ VISIT(st, expr, outermost->iter);
+ /* Create comprehension scope for the rest */
+ if (!scope_name ||
+ !symtable_enter_block(st, scope_name, FunctionBlock, (void *)e, 0)) {
+ return 0;
+ }
+ /* In order to check for yield expressions under '-3', we clear
+ the generator flag, and restore it at the end */
+ is_generator |= st->st_cur->ste_generator;
+ st->st_cur->ste_generator = 0;
+ /* Outermost iter is received as an argument */
+ if (!symtable_implicit_arg(st, 0)) {
+ symtable_exit_block(st, (void *)e);
+ return 0;
+ }
+ /* Allocate temporary name if needed */
+ if (needs_tmp && !symtable_new_tmpname(st)) {
+ symtable_exit_block(st, (void *)e);
+ return 0;
+ }
+ VISIT_IN_BLOCK(st, expr, outermost->target, (void*)e);
+ VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e);
+ VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension,
+ generators, 1, (void*)e);
+ if (value)
+ VISIT_IN_BLOCK(st, expr, value, (void*)e);
+ VISIT_IN_BLOCK(st, expr, elt, (void*)e);
+ if (Py_Py3kWarningFlag && st->st_cur->ste_generator) {
+ const char *msg = (
+ (e->kind == SetComp_kind) ? "'yield' inside set comprehension" :
+ (e->kind == DictComp_kind) ? "'yield' inside dict comprehension" :
+ "'yield' inside generator expression");
+ if (!symtable_warn(st, PyExc_DeprecationWarning, msg, -1)) {
+ symtable_exit_block(st, (void *)e);
+ return 0;
+ }
+ }
+ st->st_cur->ste_generator |= is_generator;
+ return symtable_exit_block(st, (void *)e);
+}
+
+static int
+symtable_visit_listcomp(struct symtable *st, expr_ty e)
+{
+ asdl_seq *generators = e->v.ListComp.generators;
+ int i, is_generator;
+ /* In order to check for yield expressions under '-3', we clear
+ the generator flag, and restore it at the end */
+ is_generator = st->st_cur->ste_generator;
+ st->st_cur->ste_generator = 0;
+ VISIT(st, expr, e->v.ListComp.elt);
+ for (i = 0; i < asdl_seq_LEN(generators); i++) {
+ comprehension_ty lc = (comprehension_ty)asdl_seq_GET(generators, i);
+ VISIT(st, expr, lc->target);
+ if (i == 0 && !st->st_cur->ste_generator) {
+ /* 'yield' in the outermost iterator doesn't cause a warning */
+ VISIT(st, expr, lc->iter);
+ is_generator |= st->st_cur->ste_generator;
+ st->st_cur->ste_generator = 0;
+ }
+ else {
+ VISIT(st, expr, lc->iter);
+ }
+ VISIT_SEQ(st, expr, lc->ifs);
+ }
+
+ if (Py_Py3kWarningFlag && st->st_cur->ste_generator) {
+ const char *msg = "'yield' inside list comprehension";
+ if (!symtable_warn(st, PyExc_DeprecationWarning, msg, -1)) {
+ return 0;
+ }
+ }
+ st->st_cur->ste_generator |= is_generator;
+ return 1;
+}
+
+static int
+symtable_visit_genexp(struct symtable *st, expr_ty e)
+{
+ return symtable_handle_comprehension(st, e, GET_IDENTIFIER(genexpr),
+ e->v.GeneratorExp.generators,
+ e->v.GeneratorExp.elt, NULL);
+}
+
+static int
+symtable_visit_setcomp(struct symtable *st, expr_ty e)
+{
+ return symtable_handle_comprehension(st, e, GET_IDENTIFIER(setcomp),
+ e->v.SetComp.generators,
+ e->v.SetComp.elt, NULL);
+}
+
+static int
+symtable_visit_dictcomp(struct symtable *st, expr_ty e)
+{
+ return symtable_handle_comprehension(st, e, GET_IDENTIFIER(dictcomp),
+ e->v.DictComp.generators,
+ e->v.DictComp.key,
+ e->v.DictComp.value);
+}
diff --git a/contrib/tools/python/src/Python/sysmodule.c b/contrib/tools/python/src/Python/sysmodule.c
new file mode 100644
index 0000000000..d12af0f2bc
--- /dev/null
+++ b/contrib/tools/python/src/Python/sysmodule.c
@@ -0,0 +1,1800 @@
+
+/* System module */
+
+/*
+Various bits of information used by the interpreter are collected in
+module 'sys'.
+Function member:
+- exit(sts): raise SystemExit
+Data members:
+- stdin, stdout, stderr: standard file objects
+- modules: the table of modules (dictionary)
+- path: module search path (list of strings)
+- argv: script arguments (list of strings)
+- ps1, ps2: optional primary and secondary prompts (strings)
+*/
+
+#include "Python.h"
+#include "structseq.h"
+#include "code.h"
+#include "frameobject.h"
+#include "eval.h"
+
+#include "osdefs.h"
+
+#ifdef MS_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+#endif /* MS_WINDOWS */
+
+#ifdef MS_COREDLL
+extern void *PyWin_DLLhModule;
+/* A string loaded from the DLL at startup: */
+extern const char *PyWin_DLLVersionString;
+#endif
+
+#ifdef __VMS
+#include <unixlib.h>
+#endif
+
+#ifdef MS_WINDOWS
+#include <windows.h>
+#endif
+
+#ifdef HAVE_LANGINFO_H
+#include <locale.h>
+#include <langinfo.h>
+#endif
+
+PyObject *
+PySys_GetObject(const char *name)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *sd = tstate->interp->sysdict;
+ if (sd == NULL)
+ return NULL;
+ return PyDict_GetItemString(sd, name);
+}
+
+FILE *
+PySys_GetFile(char *name, FILE *def)
+{
+ FILE *fp = NULL;
+ PyObject *v = PySys_GetObject(name);
+ if (v != NULL && PyFile_Check(v))
+ fp = PyFile_AsFile(v);
+ if (fp == NULL)
+ fp = def;
+ return fp;
+}
+
+int
+PySys_SetObject(const char *name, PyObject *v)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *sd = tstate->interp->sysdict;
+ if (v == NULL) {
+ if (PyDict_GetItemString(sd, name) == NULL)
+ return 0;
+ else
+ return PyDict_DelItemString(sd, name);
+ }
+ else
+ return PyDict_SetItemString(sd, name, v);
+}
+
+static PyObject *
+sys_displayhook(PyObject *self, PyObject *o)
+{
+ PyObject *outf;
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ PyObject *modules = interp->modules;
+ PyObject *builtins = PyDict_GetItemString(modules, "__builtin__");
+
+ if (builtins == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "lost __builtin__");
+ return NULL;
+ }
+
+ /* Print value except if None */
+ /* After printing, also assign to '_' */
+ /* Before, set '_' to None to avoid recursion */
+ if (o == Py_None) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (PyObject_SetAttrString(builtins, "_", Py_None) != 0)
+ return NULL;
+ if (Py_FlushLine() != 0)
+ return NULL;
+ outf = PySys_GetObject("stdout");
+ if (outf == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
+ return NULL;
+ }
+ if (PyFile_WriteObject(o, outf, 0) != 0)
+ return NULL;
+ PyFile_SoftSpace(outf, 1);
+ if (Py_FlushLine() != 0)
+ return NULL;
+ if (PyObject_SetAttrString(builtins, "_", o) != 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(displayhook_doc,
+"displayhook(object) -> None\n"
+"\n"
+"Print an object to sys.stdout and also save it in __builtin__._\n"
+);
+
+static PyObject *
+sys_excepthook(PyObject* self, PyObject* args)
+{
+ PyObject *exc, *value, *tb;
+ if (!PyArg_UnpackTuple(args, "excepthook", 3, 3, &exc, &value, &tb))
+ return NULL;
+ PyErr_Display(exc, value, tb);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(excepthook_doc,
+"excepthook(exctype, value, traceback) -> None\n"
+"\n"
+"Handle an exception by displaying it with a traceback on sys.stderr.\n"
+);
+
+static PyObject *
+sys_exc_info(PyObject *self, PyObject *noargs)
+{
+ PyThreadState *tstate;
+ tstate = PyThreadState_GET();
+ return Py_BuildValue(
+ "(OOO)",
+ tstate->exc_type != NULL ? tstate->exc_type : Py_None,
+ tstate->exc_value != NULL ? tstate->exc_value : Py_None,
+ tstate->exc_traceback != NULL ?
+ tstate->exc_traceback : Py_None);
+}
+
+PyDoc_STRVAR(exc_info_doc,
+"exc_info() -> (type, value, traceback)\n\
+\n\
+Return information about the most recent exception caught by an except\n\
+clause in the current stack frame or in an older stack frame."
+);
+
+static PyObject *
+sys_exc_clear(PyObject *self, PyObject *noargs)
+{
+ PyThreadState *tstate;
+ PyObject *tmp_type, *tmp_value, *tmp_tb;
+
+ if (PyErr_WarnPy3k("sys.exc_clear() not supported in 3.x; "
+ "use except clauses", 1) < 0)
+ return NULL;
+
+ tstate = PyThreadState_GET();
+ tmp_type = tstate->exc_type;
+ tmp_value = tstate->exc_value;
+ tmp_tb = tstate->exc_traceback;
+ tstate->exc_type = NULL;
+ tstate->exc_value = NULL;
+ tstate->exc_traceback = NULL;
+ Py_XDECREF(tmp_type);
+ Py_XDECREF(tmp_value);
+ Py_XDECREF(tmp_tb);
+ /* For b/w compatibility */
+ PySys_SetObject("exc_type", Py_None);
+ PySys_SetObject("exc_value", Py_None);
+ PySys_SetObject("exc_traceback", Py_None);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(exc_clear_doc,
+"exc_clear() -> None\n\
+\n\
+Clear global information on the current exception. Subsequent calls to\n\
+exc_info() will return (None,None,None) until another exception is raised\n\
+in the current thread or the execution stack returns to a frame where\n\
+another exception is being handled."
+);
+
+static PyObject *
+sys_exit(PyObject *self, PyObject *args)
+{
+ PyObject *exit_code = 0;
+ if (!PyArg_UnpackTuple(args, "exit", 0, 1, &exit_code))
+ return NULL;
+ /* Raise SystemExit so callers may catch it or clean up. */
+ PyErr_SetObject(PyExc_SystemExit, exit_code);
+ return NULL;
+}
+
+PyDoc_STRVAR(exit_doc,
+"exit([status])\n\
+\n\
+Exit the interpreter by raising SystemExit(status).\n\
+If the status is omitted or None, it defaults to zero (i.e., success).\n\
+If the status is an integer, it will be used as the system exit status.\n\
+If it is another kind of object, it will be printed and the system\n\
+exit status will be one (i.e., failure)."
+);
+
+#ifdef Py_USING_UNICODE
+
+static PyObject *
+sys_getdefaultencoding(PyObject *self)
+{
+ return PyString_FromString(PyUnicode_GetDefaultEncoding());
+}
+
+PyDoc_STRVAR(getdefaultencoding_doc,
+"getdefaultencoding() -> string\n\
+\n\
+Return the current default string encoding used by the Unicode \n\
+implementation."
+);
+
+static PyObject *
+sys_setdefaultencoding(PyObject *self, PyObject *args)
+{
+ char *encoding;
+ if (!PyArg_ParseTuple(args, "s:setdefaultencoding", &encoding))
+ return NULL;
+ if (PyUnicode_SetDefaultEncoding(encoding))
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setdefaultencoding_doc,
+"setdefaultencoding(encoding)\n\
+\n\
+Set the current default string encoding used by the Unicode implementation."
+);
+
+static PyObject *
+sys_getfilesystemencoding(PyObject *self)
+{
+ if (Py_FileSystemDefaultEncoding)
+ return PyString_FromString(Py_FileSystemDefaultEncoding);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(getfilesystemencoding_doc,
+"getfilesystemencoding() -> string\n\
+\n\
+Return the encoding used to convert Unicode filenames in\n\
+operating system filenames."
+);
+
+#endif
+
+/*
+ * Cached interned string objects used for calling the profile and
+ * trace functions. Initialized by trace_init().
+ */
+static PyObject *whatstrings[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+static int
+trace_init(void)
+{
+ static char *whatnames[7] = {"call", "exception", "line", "return",
+ "c_call", "c_exception", "c_return"};
+ PyObject *name;
+ int i;
+ for (i = 0; i < 7; ++i) {
+ if (whatstrings[i] == NULL) {
+ name = PyString_InternFromString(whatnames[i]);
+ if (name == NULL)
+ return -1;
+ whatstrings[i] = name;
+ }
+ }
+ return 0;
+}
+
+
+static PyObject *
+call_trampoline(PyThreadState *tstate, PyObject* callback,
+ PyFrameObject *frame, int what, PyObject *arg)
+{
+ PyObject *args = PyTuple_New(3);
+ PyObject *whatstr;
+ PyObject *result;
+
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(frame);
+ whatstr = whatstrings[what];
+ Py_INCREF(whatstr);
+ if (arg == NULL)
+ arg = Py_None;
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(args, 0, (PyObject *)frame);
+ PyTuple_SET_ITEM(args, 1, whatstr);
+ PyTuple_SET_ITEM(args, 2, arg);
+
+ /* call the Python-level function */
+ PyFrame_FastToLocals(frame);
+ result = PyEval_CallObject(callback, args);
+ PyFrame_LocalsToFast(frame, 1);
+ if (result == NULL)
+ PyTraceBack_Here(frame);
+
+ /* cleanup */
+ Py_DECREF(args);
+ return result;
+}
+
+static int
+profile_trampoline(PyObject *self, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ PyThreadState *tstate = frame->f_tstate;
+ PyObject *result;
+
+ if (arg == NULL)
+ arg = Py_None;
+ result = call_trampoline(tstate, self, frame, what, arg);
+ if (result == NULL) {
+ PyEval_SetProfile(NULL, NULL);
+ return -1;
+ }
+ Py_DECREF(result);
+ return 0;
+}
+
+static int
+trace_trampoline(PyObject *self, PyFrameObject *frame,
+ int what, PyObject *arg)
+{
+ PyThreadState *tstate = frame->f_tstate;
+ PyObject *callback;
+ PyObject *result;
+
+ if (what == PyTrace_CALL)
+ callback = self;
+ else
+ callback = frame->f_trace;
+ if (callback == NULL)
+ return 0;
+ result = call_trampoline(tstate, callback, frame, what, arg);
+ if (result == NULL) {
+ PyEval_SetTrace(NULL, NULL);
+ Py_CLEAR(frame->f_trace);
+ return -1;
+ }
+ if (result != Py_None) {
+ PyObject *temp = frame->f_trace;
+ frame->f_trace = NULL;
+ Py_XDECREF(temp);
+ frame->f_trace = result;
+ }
+ else {
+ Py_DECREF(result);
+ }
+ return 0;
+}
+
+static PyObject *
+sys_settrace(PyObject *self, PyObject *args)
+{
+ if (trace_init() == -1)
+ return NULL;
+ if (args == Py_None)
+ PyEval_SetTrace(NULL, NULL);
+ else
+ PyEval_SetTrace(trace_trampoline, args);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(settrace_doc,
+"settrace(function)\n\
+\n\
+Set the global debug tracing function. It will be called on each\n\
+function call. See the debugger chapter in the library manual."
+);
+
+static PyObject *
+sys_gettrace(PyObject *self, PyObject *args)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *temp = tstate->c_traceobj;
+
+ if (temp == NULL)
+ temp = Py_None;
+ Py_INCREF(temp);
+ return temp;
+}
+
+PyDoc_STRVAR(gettrace_doc,
+"gettrace()\n\
+\n\
+Return the global debug tracing function set with sys.settrace.\n\
+See the debugger chapter in the library manual."
+);
+
+static PyObject *
+sys_setprofile(PyObject *self, PyObject *args)
+{
+ if (trace_init() == -1)
+ return NULL;
+ if (args == Py_None)
+ PyEval_SetProfile(NULL, NULL);
+ else
+ PyEval_SetProfile(profile_trampoline, args);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setprofile_doc,
+"setprofile(function)\n\
+\n\
+Set the profiling function. It will be called on each function call\n\
+and return. See the profiler chapter in the library manual."
+);
+
+static PyObject *
+sys_getprofile(PyObject *self, PyObject *args)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *temp = tstate->c_profileobj;
+
+ if (temp == NULL)
+ temp = Py_None;
+ Py_INCREF(temp);
+ return temp;
+}
+
+PyDoc_STRVAR(getprofile_doc,
+"getprofile()\n\
+\n\
+Return the profiling function set with sys.setprofile.\n\
+See the profiler chapter in the library manual."
+);
+
+static PyObject *
+sys_setcheckinterval(PyObject *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "i:setcheckinterval", &_Py_CheckInterval))
+ return NULL;
+ _Py_Ticker = _Py_CheckInterval;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setcheckinterval_doc,
+"setcheckinterval(n)\n\
+\n\
+Tell the Python interpreter to check for asynchronous events every\n\
+n instructions. This also affects how often thread switches occur."
+);
+
+static PyObject *
+sys_getcheckinterval(PyObject *self, PyObject *args)
+{
+ return PyInt_FromLong(_Py_CheckInterval);
+}
+
+PyDoc_STRVAR(getcheckinterval_doc,
+"getcheckinterval() -> current check interval; see setcheckinterval()."
+);
+
+#ifdef WITH_TSC
+static PyObject *
+sys_settscdump(PyObject *self, PyObject *args)
+{
+ int bool;
+ PyThreadState *tstate = PyThreadState_Get();
+
+ if (!PyArg_ParseTuple(args, "i:settscdump", &bool))
+ return NULL;
+ if (bool)
+ tstate->interp->tscdump = 1;
+ else
+ tstate->interp->tscdump = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
+
+}
+
+PyDoc_STRVAR(settscdump_doc,
+"settscdump(bool)\n\
+\n\
+If true, tell the Python interpreter to dump VM measurements to\n\
+stderr. If false, turn off dump. The measurements are based on the\n\
+processor's time-stamp counter."
+);
+#endif /* TSC */
+
+static PyObject *
+sys_setrecursionlimit(PyObject *self, PyObject *args)
+{
+ int new_limit;
+ if (!PyArg_ParseTuple(args, "i:setrecursionlimit", &new_limit))
+ return NULL;
+ if (new_limit <= 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "recursion limit must be positive");
+ return NULL;
+ }
+ Py_SetRecursionLimit(new_limit);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setrecursionlimit_doc,
+"setrecursionlimit(n)\n\
+\n\
+Set the maximum depth of the Python interpreter stack to n. This\n\
+limit prevents infinite recursion from causing an overflow of the C\n\
+stack and crashing Python. The highest possible limit is platform-\n\
+dependent."
+);
+
+static PyObject *
+sys_getrecursionlimit(PyObject *self)
+{
+ return PyInt_FromLong(Py_GetRecursionLimit());
+}
+
+PyDoc_STRVAR(getrecursionlimit_doc,
+"getrecursionlimit()\n\
+\n\
+Return the current value of the recursion limit, the maximum depth\n\
+of the Python interpreter stack. This limit prevents infinite\n\
+recursion from causing an overflow of the C stack and crashing Python."
+);
+
+#ifdef MS_WINDOWS
+PyDoc_STRVAR(getwindowsversion_doc,
+"getwindowsversion()\n\
+\n\
+Return information about the running version of Windows as a named tuple.\n\
+The members are named: major, minor, build, platform, service_pack,\n\
+service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\
+backward compatibility, only the first 5 items are available by indexing.\n\
+All elements are numbers, except service_pack which is a string. Platform\n\
+may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\
+3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\
+controller, 3 for a server."
+);
+
+static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0};
+
+static PyStructSequence_Field windows_version_fields[] = {
+ {"major", "Major version number"},
+ {"minor", "Minor version number"},
+ {"build", "Build number"},
+ {"platform", "Operating system platform"},
+ {"service_pack", "Latest Service Pack installed on the system"},
+ {"service_pack_major", "Service Pack major version number"},
+ {"service_pack_minor", "Service Pack minor version number"},
+ {"suite_mask", "Bit mask identifying available product suites"},
+ {"product_type", "System product type"},
+ {0}
+};
+
+static PyStructSequence_Desc windows_version_desc = {
+ "sys.getwindowsversion", /* name */
+ getwindowsversion_doc, /* doc */
+ windows_version_fields, /* fields */
+ 5 /* For backward compatibility,
+ only the first 5 items are accessible
+ via indexing, the rest are name only */
+};
+
+static PyObject *
+sys_getwindowsversion(PyObject *self)
+{
+ PyObject *version;
+ int pos = 0;
+ OSVERSIONINFOEX ver;
+ ver.dwOSVersionInfoSize = sizeof(ver);
+ if (!GetVersionEx((OSVERSIONINFO*) &ver))
+ return PyErr_SetFromWindowsErr(0);
+
+ version = PyStructSequence_New(&WindowsVersionType);
+ if (version == NULL)
+ return NULL;
+
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.dwMajorVersion));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.dwMinorVersion));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.dwBuildNumber));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.dwPlatformId));
+ PyStructSequence_SET_ITEM(version, pos++, PyString_FromString(ver.szCSDVersion));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.wServicePackMajor));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.wServicePackMinor));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.wSuiteMask));
+ PyStructSequence_SET_ITEM(version, pos++, PyInt_FromLong(ver.wProductType));
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(version);
+ return NULL;
+ }
+ return version;
+}
+
+#endif /* MS_WINDOWS */
+
+#ifdef HAVE_DLOPEN
+static PyObject *
+sys_setdlopenflags(PyObject *self, PyObject *args)
+{
+ int new_val;
+ PyThreadState *tstate = PyThreadState_GET();
+ if (!PyArg_ParseTuple(args, "i:setdlopenflags", &new_val))
+ return NULL;
+ if (!tstate)
+ return NULL;
+ tstate->interp->dlopenflags = new_val;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(setdlopenflags_doc,
+"setdlopenflags(n) -> None\n\
+\n\
+Set the flags used by the interpreter for dlopen calls, such as when the\n\
+interpreter loads extension modules. Among other things, this will enable\n\
+a lazy resolving of symbols when importing a module, if called as\n\
+sys.setdlopenflags(0). To share symbols across extension modules, call as\n\
+sys.setdlopenflags(ctypes.RTLD_GLOBAL). Symbolic names for the flag modules\n\
+can be either found in the ctypes module, or in the DLFCN module. If DLFCN\n\
+is not available, it can be generated from /usr/include/dlfcn.h using the\n\
+h2py script.");
+
+static PyObject *
+sys_getdlopenflags(PyObject *self, PyObject *args)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ if (!tstate)
+ return NULL;
+ return PyInt_FromLong(tstate->interp->dlopenflags);
+}
+
+PyDoc_STRVAR(getdlopenflags_doc,
+"getdlopenflags() -> int\n\
+\n\
+Return the current value of the flags that are used for dlopen calls.\n\
+The flag constants are defined in the ctypes and DLFCN modules.");
+
+#endif /* HAVE_DLOPEN */
+
+#ifdef USE_MALLOPT
+/* Link with -lmalloc (or -lmpc) on an SGI */
+#include <malloc.h>
+
+static PyObject *
+sys_mdebug(PyObject *self, PyObject *args)
+{
+ int flag;
+ if (!PyArg_ParseTuple(args, "i:mdebug", &flag))
+ return NULL;
+ mallopt(M_DEBUG, flag);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif /* USE_MALLOPT */
+
+size_t
+_PySys_GetSizeOf(PyObject *o)
+{
+ static PyObject *str__sizeof__ = NULL;
+ PyObject *res = NULL;
+ Py_ssize_t size;
+
+ /* Make sure the type is initialized. float gets initialized late */
+ if (PyType_Ready(Py_TYPE(o)) < 0)
+ return (size_t)-1;
+
+ /* Instance of old-style class */
+ if (PyInstance_Check(o))
+ size = PyInstance_Type.tp_basicsize;
+ /* all other objects */
+ else {
+ PyObject *method = _PyObject_LookupSpecial(o, "__sizeof__",
+ &str__sizeof__);
+ if (method == NULL) {
+ if (!PyErr_Occurred())
+ PyErr_Format(PyExc_TypeError,
+ "Type %.100s doesn't define __sizeof__",
+ Py_TYPE(o)->tp_name);
+ }
+ else {
+ res = PyObject_CallFunctionObjArgs(method, NULL);
+ Py_DECREF(method);
+ }
+
+ if (res == NULL)
+ return (size_t)-1;
+
+ size = (size_t)PyInt_AsSsize_t(res);
+ Py_DECREF(res);
+ if (size == -1 && PyErr_Occurred())
+ return (size_t)-1;
+ }
+
+ if (size < 0) {
+ PyErr_SetString(PyExc_ValueError, "__sizeof__() should return >= 0");
+ return (size_t)-1;
+ }
+
+ /* add gc_head size */
+ if (PyObject_IS_GC(o))
+ return ((size_t)size) + sizeof(PyGC_Head);
+ return (size_t)size;
+}
+
+static PyObject *
+sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"object", "default", 0};
+ size_t size;
+ PyObject *o, *dflt = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof",
+ kwlist, &o, &dflt))
+ return NULL;
+
+ size = _PySys_GetSizeOf(o);
+
+ if (size == (size_t)-1 && PyErr_Occurred()) {
+ /* Has a default value been given */
+ if (dflt != NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_Clear();
+ Py_INCREF(dflt);
+ return dflt;
+ }
+ else
+ return NULL;
+ }
+
+ return PyInt_FromSize_t(size);
+}
+
+PyDoc_STRVAR(getsizeof_doc,
+"getsizeof(object, default) -> int\n\
+\n\
+Return the size of object in bytes.");
+
+static PyObject *
+sys_getrefcount(PyObject *self, PyObject *arg)
+{
+ return PyInt_FromSsize_t(arg->ob_refcnt);
+}
+
+#ifdef Py_REF_DEBUG
+static PyObject *
+sys_gettotalrefcount(PyObject *self)
+{
+ return PyInt_FromSsize_t(_Py_GetRefTotal());
+}
+#endif /* Py_REF_DEBUG */
+
+PyDoc_STRVAR(getrefcount_doc,
+"getrefcount(object) -> integer\n\
+\n\
+Return the reference count of object. The count returned is generally\n\
+one higher than you might expect, because it includes the (temporary)\n\
+reference as an argument to getrefcount()."
+);
+
+#ifdef COUNT_ALLOCS
+static PyObject *
+sys_getcounts(PyObject *self)
+{
+ extern PyObject *get_counts(void);
+
+ return get_counts();
+}
+#endif
+
+PyDoc_STRVAR(getframe_doc,
+"_getframe([depth]) -> frameobject\n\
+\n\
+Return a frame object from the call stack. If optional integer depth is\n\
+given, return the frame object that many calls below the top of the stack.\n\
+If that is deeper than the call stack, ValueError is raised. The default\n\
+for depth is zero, returning the frame at the top of the call stack.\n\
+\n\
+This function should be used for internal and specialized\n\
+purposes only."
+);
+
+static PyObject *
+sys_getframe(PyObject *self, PyObject *args)
+{
+ PyFrameObject *f = PyThreadState_GET()->frame;
+ int depth = -1;
+
+ if (!PyArg_ParseTuple(args, "|i:_getframe", &depth))
+ return NULL;
+
+ while (depth > 0 && f != NULL) {
+ f = f->f_back;
+ --depth;
+ }
+ if (f == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "call stack is not deep enough");
+ return NULL;
+ }
+ Py_INCREF(f);
+ return (PyObject*)f;
+}
+
+PyDoc_STRVAR(current_frames_doc,
+"_current_frames() -> dictionary\n\
+\n\
+Return a dictionary mapping each current thread T's thread id to T's\n\
+current stack frame.\n\
+\n\
+This function should be used for specialized purposes only."
+);
+
+static PyObject *
+sys_current_frames(PyObject *self, PyObject *noargs)
+{
+ return _PyThread_CurrentFrames();
+}
+
+PyDoc_STRVAR(call_tracing_doc,
+"call_tracing(func, args) -> object\n\
+\n\
+Call func(*args), while tracing is enabled. The tracing state is\n\
+saved, and restored afterwards. This is intended to be called from\n\
+a debugger from a checkpoint, to recursively debug some other code."
+);
+
+static PyObject *
+sys_call_tracing(PyObject *self, PyObject *args)
+{
+ PyObject *func, *funcargs;
+ if (!PyArg_ParseTuple(args, "OO!:call_tracing", &func, &PyTuple_Type, &funcargs))
+ return NULL;
+ return _PyEval_CallTracing(func, funcargs);
+}
+
+PyDoc_STRVAR(callstats_doc,
+"callstats() -> tuple of integers\n\
+\n\
+Return a tuple of function call statistics, if CALL_PROFILE was defined\n\
+when Python was built. Otherwise, return None.\n\
+\n\
+When enabled, this function returns detailed, implementation-specific\n\
+details about the number of function calls executed. The return value is\n\
+a 11-tuple where the entries in the tuple are counts of:\n\
+0. all function calls\n\
+1. calls to PyFunction_Type objects\n\
+2. PyFunction calls that do not create an argument tuple\n\
+3. PyFunction calls that do not create an argument tuple\n\
+ and bypass PyEval_EvalCodeEx()\n\
+4. PyMethod calls\n\
+5. PyMethod calls on bound methods\n\
+6. PyType calls\n\
+7. PyCFunction calls\n\
+8. generator calls\n\
+9. All other calls\n\
+10. Number of stack pops performed by call_function()"
+);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef Py_TRACE_REFS
+/* Defined in objects.c because it uses static globals if that file */
+extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
+#endif
+
+#ifdef DYNAMIC_EXECUTION_PROFILE
+/* Defined in ceval.c because it uses static globals if that file */
+extern PyObject *_Py_GetDXProfile(PyObject *, PyObject *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+static PyObject *
+sys_clear_type_cache(PyObject* self, PyObject* args)
+{
+ PyType_ClearCache();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(sys_clear_type_cache__doc__,
+"_clear_type_cache() -> None\n\
+Clear the internal type lookup cache.");
+
+
+static PyMethodDef sys_methods[] = {
+ /* Might as well keep this in alphabetic order */
+ {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS,
+ callstats_doc},
+ {"_clear_type_cache", sys_clear_type_cache, METH_NOARGS,
+ sys_clear_type_cache__doc__},
+ {"_current_frames", sys_current_frames, METH_NOARGS,
+ current_frames_doc},
+ {"displayhook", sys_displayhook, METH_O, displayhook_doc},
+ {"exc_info", sys_exc_info, METH_NOARGS, exc_info_doc},
+ {"exc_clear", sys_exc_clear, METH_NOARGS, exc_clear_doc},
+ {"excepthook", sys_excepthook, METH_VARARGS, excepthook_doc},
+ {"exit", sys_exit, METH_VARARGS, exit_doc},
+#ifdef Py_USING_UNICODE
+ {"getdefaultencoding", (PyCFunction)sys_getdefaultencoding,
+ METH_NOARGS, getdefaultencoding_doc},
+#endif
+#ifdef HAVE_DLOPEN
+ {"getdlopenflags", (PyCFunction)sys_getdlopenflags, METH_NOARGS,
+ getdlopenflags_doc},
+#endif
+#ifdef COUNT_ALLOCS
+ {"getcounts", (PyCFunction)sys_getcounts, METH_NOARGS},
+#endif
+#ifdef DYNAMIC_EXECUTION_PROFILE
+ {"getdxp", _Py_GetDXProfile, METH_VARARGS},
+#endif
+#ifdef Py_USING_UNICODE
+ {"getfilesystemencoding", (PyCFunction)sys_getfilesystemencoding,
+ METH_NOARGS, getfilesystemencoding_doc},
+#endif
+#ifdef Py_TRACE_REFS
+ {"getobjects", _Py_GetObjects, METH_VARARGS},
+#endif
+#ifdef Py_REF_DEBUG
+ {"gettotalrefcount", (PyCFunction)sys_gettotalrefcount, METH_NOARGS},
+#endif
+ {"getrefcount", (PyCFunction)sys_getrefcount, METH_O, getrefcount_doc},
+ {"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS,
+ getrecursionlimit_doc},
+ {"getsizeof", (PyCFunction)sys_getsizeof,
+ METH_VARARGS | METH_KEYWORDS, getsizeof_doc},
+ {"_getframe", sys_getframe, METH_VARARGS, getframe_doc},
+#ifdef MS_WINDOWS
+ {"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS,
+ getwindowsversion_doc},
+#endif /* MS_WINDOWS */
+#ifdef USE_MALLOPT
+ {"mdebug", sys_mdebug, METH_VARARGS},
+#endif
+#ifdef Py_USING_UNICODE
+ {"setdefaultencoding", sys_setdefaultencoding, METH_VARARGS,
+ setdefaultencoding_doc},
+#endif
+ {"setcheckinterval", sys_setcheckinterval, METH_VARARGS,
+ setcheckinterval_doc},
+ {"getcheckinterval", sys_getcheckinterval, METH_NOARGS,
+ getcheckinterval_doc},
+#ifdef HAVE_DLOPEN
+ {"setdlopenflags", sys_setdlopenflags, METH_VARARGS,
+ setdlopenflags_doc},
+#endif
+ {"setprofile", sys_setprofile, METH_O, setprofile_doc},
+ {"getprofile", sys_getprofile, METH_NOARGS, getprofile_doc},
+ {"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS,
+ setrecursionlimit_doc},
+#ifdef WITH_TSC
+ {"settscdump", sys_settscdump, METH_VARARGS, settscdump_doc},
+#endif
+ {"settrace", sys_settrace, METH_O, settrace_doc},
+ {"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc},
+ {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+list_builtin_module_names(void)
+{
+ PyObject *list = PyList_New(0);
+ int i;
+ if (list == NULL)
+ return NULL;
+ for (i = 0; PyImport_Inittab[i].name != NULL; i++) {
+ PyObject *name = PyString_FromString(
+ PyImport_Inittab[i].name);
+ if (name == NULL)
+ break;
+ PyList_Append(list, name);
+ Py_DECREF(name);
+ }
+ if (PyList_Sort(list) != 0) {
+ Py_DECREF(list);
+ list = NULL;
+ }
+ if (list) {
+ PyObject *v = PyList_AsTuple(list);
+ Py_DECREF(list);
+ list = v;
+ }
+ return list;
+}
+
+static PyObject *warnoptions = NULL;
+
+void
+PySys_ResetWarnOptions(void)
+{
+ if (warnoptions == NULL || !PyList_Check(warnoptions))
+ return;
+ PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL);
+}
+
+void
+PySys_AddWarnOption(char *s)
+{
+ PyObject *str;
+
+ if (warnoptions == NULL || !PyList_Check(warnoptions)) {
+ Py_XDECREF(warnoptions);
+ warnoptions = PyList_New(0);
+ if (warnoptions == NULL)
+ return;
+ }
+ str = PyString_FromString(s);
+ if (str != NULL) {
+ PyList_Append(warnoptions, str);
+ Py_DECREF(str);
+ }
+}
+
+int
+PySys_HasWarnOptions(void)
+{
+ return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
+}
+
+/* XXX This doc string is too long to be a single string literal in VC++ 5.0.
+ Two literals concatenated works just fine. If you have a K&R compiler
+ or other abomination that however *does* understand longer strings,
+ get rid of the !!! comment in the middle and the quotes that surround it. */
+PyDoc_VAR(sys_doc) =
+PyDoc_STR(
+"This module provides access to some objects used or maintained by the\n\
+interpreter and to functions that interact strongly with the interpreter.\n\
+\n\
+Dynamic objects:\n\
+\n\
+argv -- command line arguments; argv[0] is the script pathname if known\n\
+path -- module search path; path[0] is the script directory, else ''\n\
+modules -- dictionary of loaded modules\n\
+\n\
+displayhook -- called to show results in an interactive session\n\
+excepthook -- called to handle any uncaught exception other than SystemExit\n\
+ To customize printing in an interactive session or to install a custom\n\
+ top-level exception handler, assign other functions to replace these.\n\
+\n\
+exitfunc -- if sys.exitfunc exists, this routine is called when Python exits\n\
+ Assigning to sys.exitfunc is deprecated; use the atexit module instead.\n\
+\n\
+stdin -- standard input file object; used by raw_input() and input()\n\
+stdout -- standard output file object; used by the print statement\n\
+stderr -- standard error object; used for error messages\n\
+ By assigning other file objects (or objects that behave like files)\n\
+ to these, it is possible to redirect all of the interpreter's I/O.\n\
+\n\
+last_type -- type of last uncaught exception\n\
+last_value -- value of last uncaught exception\n\
+last_traceback -- traceback of last uncaught exception\n\
+ These three are only available in an interactive session after a\n\
+ traceback has been printed.\n\
+\n\
+exc_type -- type of exception currently being handled\n\
+exc_value -- value of exception currently being handled\n\
+exc_traceback -- traceback of exception currently being handled\n\
+ The function exc_info() should be used instead of these three,\n\
+ because it is thread-safe.\n\
+"
+)
+/* concatenating string here */
+PyDoc_STR(
+"\n\
+Static objects:\n\
+\n\
+float_info -- a dict with information about the float inplementation.\n\
+long_info -- a struct sequence with information about the long implementation.\n\
+maxint -- the largest supported integer (the smallest is -maxint-1)\n\
+maxsize -- the largest supported length of containers.\n\
+maxunicode -- the largest supported character\n\
+builtin_module_names -- tuple of module names built into this interpreter\n\
+version -- the version of this interpreter as a string\n\
+version_info -- version information as a named tuple\n\
+hexversion -- version information encoded as a single integer\n\
+copyright -- copyright notice pertaining to this interpreter\n\
+platform -- platform identifier\n\
+executable -- absolute path of the executable binary of the Python interpreter\n\
+prefix -- prefix used to find the Python library\n\
+exec_prefix -- prefix used to find the machine-specific Python library\n\
+float_repr_style -- string indicating the style of repr() output for floats\n\
+"
+)
+#ifdef MS_WINDOWS
+/* concatenating string here */
+PyDoc_STR(
+"dllhandle -- [Windows only] integer handle of the Python DLL\n\
+winver -- [Windows only] version number of the Python DLL\n\
+"
+)
+#endif /* MS_WINDOWS */
+PyDoc_STR(
+"__stdin__ -- the original stdin; don't touch!\n\
+__stdout__ -- the original stdout; don't touch!\n\
+__stderr__ -- the original stderr; don't touch!\n\
+__displayhook__ -- the original displayhook; don't touch!\n\
+__excepthook__ -- the original excepthook; don't touch!\n\
+\n\
+Functions:\n\
+\n\
+displayhook() -- print an object to the screen, and save it in __builtin__._\n\
+excepthook() -- print an exception and its traceback to sys.stderr\n\
+exc_info() -- return thread-safe information about the current exception\n\
+exc_clear() -- clear the exception state for the current thread\n\
+exit() -- exit the interpreter by raising SystemExit\n\
+getdlopenflags() -- returns flags to be used for dlopen() calls\n\
+getprofile() -- get the global profiling function\n\
+getrefcount() -- return the reference count for an object (plus one :-)\n\
+getrecursionlimit() -- return the max recursion depth for the interpreter\n\
+getsizeof() -- return the size of an object in bytes\n\
+gettrace() -- get the global debug tracing function\n\
+setcheckinterval() -- control how often the interpreter checks for events\n\
+setdlopenflags() -- set the flags to be used for dlopen() calls\n\
+setprofile() -- set the global profiling function\n\
+setrecursionlimit() -- set the max recursion depth for the interpreter\n\
+settrace() -- set the global debug tracing function\n\
+"
+)
+/* end of sys_doc */ ;
+
+static int
+_check_and_flush (FILE *stream)
+{
+ int prev_fail = ferror (stream);
+ return fflush (stream) || prev_fail ? EOF : 0;
+}
+
+/* Subversion branch and revision management */
+static int svn_initialized;
+static char patchlevel_revision[50]; /* Just the number */
+static char branch[50];
+static char shortbranch[50];
+static const char *svn_revision;
+
+static void
+svnversion_init(void)
+{
+ if (svn_initialized)
+ return;
+ svn_initialized = 1;
+ *patchlevel_revision = '\0';
+ strcpy(branch, "");
+ strcpy(shortbranch, "unknown");
+ svn_revision = "";
+ return;
+}
+
+/* Return svnversion output if available.
+ Else return Revision of patchlevel.h if on branch.
+ Else return empty string */
+const char*
+Py_SubversionRevision()
+{
+ svnversion_init();
+ return svn_revision;
+}
+
+const char*
+Py_SubversionShortBranch()
+{
+ svnversion_init();
+ return shortbranch;
+}
+
+
+PyDoc_STRVAR(flags__doc__,
+"sys.flags\n\
+\n\
+Flags provided through command line arguments or environment vars.");
+
+static PyTypeObject FlagsType = {0, 0, 0, 0, 0, 0};
+
+static PyStructSequence_Field flags_fields[] = {
+ {"debug", "-d"},
+ {"py3k_warning", "-3"},
+ {"division_warning", "-Q"},
+ {"division_new", "-Qnew"},
+ {"inspect", "-i"},
+ {"interactive", "-i"},
+ {"optimize", "-O or -OO"},
+ {"dont_write_bytecode", "-B"},
+ {"no_user_site", "-s"},
+ {"no_site", "-S"},
+ {"ignore_environment", "-E"},
+ {"tabcheck", "-t or -tt"},
+ {"verbose", "-v"},
+#ifdef RISCOS
+ {"riscos_wimp", "???"},
+#endif
+ /* {"unbuffered", "-u"}, */
+ {"unicode", "-U"},
+ /* {"skip_first", "-x"}, */
+ {"bytes_warning", "-b"},
+ {"hash_randomization", "-R"},
+ {0}
+};
+
+static PyStructSequence_Desc flags_desc = {
+ "sys.flags", /* name */
+ flags__doc__, /* doc */
+ flags_fields, /* fields */
+#ifdef RISCOS
+ 17
+#else
+ 16
+#endif
+};
+
+static PyObject*
+make_flags(void)
+{
+ int pos = 0;
+ PyObject *seq;
+
+ seq = PyStructSequence_New(&FlagsType);
+ if (seq == NULL)
+ return NULL;
+
+#define SetFlag(flag) \
+ PyStructSequence_SET_ITEM(seq, pos++, PyInt_FromLong(flag))
+
+ SetFlag(Py_DebugFlag);
+ SetFlag(Py_Py3kWarningFlag);
+ SetFlag(Py_DivisionWarningFlag);
+ SetFlag(_Py_QnewFlag);
+ SetFlag(Py_InspectFlag);
+ SetFlag(Py_InteractiveFlag);
+ SetFlag(Py_OptimizeFlag);
+ SetFlag(Py_DontWriteBytecodeFlag);
+ SetFlag(Py_NoUserSiteDirectory);
+ SetFlag(Py_NoSiteFlag);
+ SetFlag(Py_IgnoreEnvironmentFlag);
+ SetFlag(Py_TabcheckFlag);
+ SetFlag(Py_VerboseFlag);
+#ifdef RISCOS
+ SetFlag(Py_RISCOSWimpFlag);
+#endif
+ /* SetFlag(saw_unbuffered_flag); */
+ SetFlag(Py_UnicodeFlag);
+ /* SetFlag(skipfirstline); */
+ SetFlag(Py_BytesWarningFlag);
+ SetFlag(Py_HashRandomizationFlag);
+#undef SetFlag
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(seq);
+ return NULL;
+ }
+ return seq;
+}
+
+PyDoc_STRVAR(version_info__doc__,
+"sys.version_info\n\
+\n\
+Version information as a named tuple.");
+
+static PyTypeObject VersionInfoType = {0, 0, 0, 0, 0, 0};
+
+static PyStructSequence_Field version_info_fields[] = {
+ {"major", "Major release number"},
+ {"minor", "Minor release number"},
+ {"micro", "Patch release number"},
+ {"releaselevel", "'alpha', 'beta', 'candidate', or 'final'"},
+ {"serial", "Serial release number"},
+ {0}
+};
+
+static PyStructSequence_Desc version_info_desc = {
+ "sys.version_info", /* name */
+ version_info__doc__, /* doc */
+ version_info_fields, /* fields */
+ 5
+};
+
+static PyObject *
+make_version_info(void)
+{
+ PyObject *version_info;
+ char *s;
+ int pos = 0;
+
+ version_info = PyStructSequence_New(&VersionInfoType);
+ if (version_info == NULL) {
+ return NULL;
+ }
+
+ /*
+ * These release level checks are mutually exclusive and cover
+ * the field, so don't get too fancy with the pre-processor!
+ */
+#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA
+ s = "alpha";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA
+ s = "beta";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA
+ s = "candidate";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL
+ s = "final";
+#endif
+
+#define SetIntItem(flag) \
+ PyStructSequence_SET_ITEM(version_info, pos++, PyInt_FromLong(flag))
+#define SetStrItem(flag) \
+ PyStructSequence_SET_ITEM(version_info, pos++, PyString_FromString(flag))
+
+ SetIntItem(PY_MAJOR_VERSION);
+ SetIntItem(PY_MINOR_VERSION);
+ SetIntItem(PY_MICRO_VERSION);
+ SetStrItem(s);
+ SetIntItem(PY_RELEASE_SERIAL);
+#undef SetIntItem
+#undef SetStrItem
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(version_info);
+ return NULL;
+ }
+ return version_info;
+}
+
+PyObject *
+_PySys_Init(void)
+{
+ PyObject *m, *v, *sysdict;
+ PyObject *sysin, *sysout, *syserr;
+ char *s;
+
+ m = Py_InitModule3("sys", sys_methods, sys_doc);
+ if (m == NULL)
+ return NULL;
+ sysdict = PyModule_GetDict(m);
+#define SET_SYS_FROM_STRING(key, value) \
+ v = value; \
+ if (v != NULL) \
+ PyDict_SetItemString(sysdict, key, v); \
+ Py_XDECREF(v)
+
+ /* Check that stdin is not a directory
+ Using shell redirection, you can redirect stdin to a directory,
+ crashing the Python interpreter. Catch this common mistake here
+ and output a useful error message. Note that under MS Windows,
+ the shell already prevents that. */
+#if !defined(MS_WINDOWS)
+ {
+ struct stat sb;
+ if (fstat(fileno(stdin), &sb) == 0 &&
+ S_ISDIR(sb.st_mode)) {
+ /* There's nothing more we can do. */
+ /* Py_FatalError() will core dump, so just exit. */
+ PySys_WriteStderr("Python error: <stdin> is a directory, cannot continue\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
+ /* Closing the standard FILE* if sys.std* goes aways causes problems
+ * for embedded Python usages. Closing them when somebody explicitly
+ * invokes .close() might be possible, but the FAQ promises they get
+ * never closed. However, we still need to get write errors when
+ * writing fails (e.g. because stdout is redirected), so we flush the
+ * streams and check for errors before the file objects are deleted.
+ * On OS X, fflush()ing stdin causes an error, so we exempt stdin
+ * from that procedure.
+ */
+ sysin = PyFile_FromFile(stdin, "<stdin>", "r", NULL);
+ sysout = PyFile_FromFile(stdout, "<stdout>", "w", _check_and_flush);
+ syserr = PyFile_FromFile(stderr, "<stderr>", "w", _check_and_flush);
+ if (PyErr_Occurred())
+ return NULL;
+
+ PyDict_SetItemString(sysdict, "stdin", sysin);
+ PyDict_SetItemString(sysdict, "stdout", sysout);
+ PyDict_SetItemString(sysdict, "stderr", syserr);
+ /* Make backup copies for cleanup */
+ PyDict_SetItemString(sysdict, "__stdin__", sysin);
+ PyDict_SetItemString(sysdict, "__stdout__", sysout);
+ PyDict_SetItemString(sysdict, "__stderr__", syserr);
+ PyDict_SetItemString(sysdict, "__displayhook__",
+ PyDict_GetItemString(sysdict, "displayhook"));
+ PyDict_SetItemString(sysdict, "__excepthook__",
+ PyDict_GetItemString(sysdict, "excepthook"));
+ Py_XDECREF(sysin);
+ Py_XDECREF(sysout);
+ Py_XDECREF(syserr);
+
+ SET_SYS_FROM_STRING("version",
+ PyString_FromString(Py_GetVersion()));
+ SET_SYS_FROM_STRING("hexversion",
+ PyInt_FromLong(PY_VERSION_HEX));
+ svnversion_init();
+ SET_SYS_FROM_STRING("subversion",
+ Py_BuildValue("(ssz)", "CPython", branch,
+ svn_revision));
+ SET_SYS_FROM_STRING("_git",
+ Py_BuildValue("(szz)", "CPython", _Py_gitidentifier(),
+ _Py_gitversion()));
+ SET_SYS_FROM_STRING("dont_write_bytecode",
+ PyBool_FromLong(Py_DontWriteBytecodeFlag));
+ SET_SYS_FROM_STRING("api_version",
+ PyInt_FromLong(PYTHON_API_VERSION));
+ SET_SYS_FROM_STRING("copyright",
+ PyString_FromString(Py_GetCopyright()));
+ SET_SYS_FROM_STRING("platform",
+ PyString_FromString(Py_GetPlatform()));
+ SET_SYS_FROM_STRING("executable",
+ PyString_FromString(Py_GetProgramFullPath()));
+ SET_SYS_FROM_STRING("prefix",
+ PyString_FromString(Py_GetPrefix()));
+ SET_SYS_FROM_STRING("exec_prefix",
+ PyString_FromString(Py_GetExecPrefix()));
+ SET_SYS_FROM_STRING("maxsize",
+ PyInt_FromSsize_t(PY_SSIZE_T_MAX));
+ SET_SYS_FROM_STRING("maxint",
+ PyInt_FromLong(PyInt_GetMax()));
+ SET_SYS_FROM_STRING("py3kwarning",
+ PyBool_FromLong(Py_Py3kWarningFlag));
+ SET_SYS_FROM_STRING("float_info",
+ PyFloat_GetInfo());
+ SET_SYS_FROM_STRING("long_info",
+ PyLong_GetInfo());
+#ifdef Py_USING_UNICODE
+ SET_SYS_FROM_STRING("maxunicode",
+ PyInt_FromLong(PyUnicode_GetMax()));
+#endif
+ SET_SYS_FROM_STRING("builtin_module_names",
+ list_builtin_module_names());
+ {
+ /* Assumes that longs are at least 2 bytes long.
+ Should be safe! */
+ unsigned long number = 1;
+ char *value;
+
+ s = (char *) &number;
+ if (s[0] == 0)
+ value = "big";
+ else
+ value = "little";
+ SET_SYS_FROM_STRING("byteorder",
+ PyString_FromString(value));
+ }
+#ifdef MS_COREDLL
+ SET_SYS_FROM_STRING("dllhandle",
+ PyLong_FromVoidPtr(PyWin_DLLhModule));
+ SET_SYS_FROM_STRING("winver",
+ PyString_FromString(PyWin_DLLVersionString));
+#endif
+ if (warnoptions == NULL) {
+ warnoptions = PyList_New(0);
+ }
+ else {
+ Py_INCREF(warnoptions);
+ }
+ if (warnoptions != NULL) {
+ PyDict_SetItemString(sysdict, "warnoptions", warnoptions);
+ }
+
+ /* version_info */
+ if (VersionInfoType.tp_name == 0)
+ PyStructSequence_InitType(&VersionInfoType, &version_info_desc);
+ SET_SYS_FROM_STRING("version_info", make_version_info());
+ /* prevent user from creating new instances */
+ VersionInfoType.tp_init = NULL;
+ VersionInfoType.tp_new = NULL;
+
+ /* flags */
+ if (FlagsType.tp_name == 0)
+ PyStructSequence_InitType(&FlagsType, &flags_desc);
+ SET_SYS_FROM_STRING("flags", make_flags());
+ /* prevent user from creating new instances */
+ FlagsType.tp_init = NULL;
+ FlagsType.tp_new = NULL;
+
+
+#if defined(MS_WINDOWS)
+ /* getwindowsversion */
+ if (WindowsVersionType.tp_name == 0)
+ PyStructSequence_InitType(&WindowsVersionType, &windows_version_desc);
+ /* prevent user from creating new instances */
+ WindowsVersionType.tp_init = NULL;
+ WindowsVersionType.tp_new = NULL;
+#endif
+
+ /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */
+#ifndef PY_NO_SHORT_FLOAT_REPR
+ SET_SYS_FROM_STRING("float_repr_style",
+ PyString_FromString("short"));
+#else
+ SET_SYS_FROM_STRING("float_repr_style",
+ PyString_FromString("legacy"));
+#endif
+
+#undef SET_SYS_FROM_STRING
+ if (PyErr_Occurred())
+ return NULL;
+ return m;
+}
+
+static PyObject *
+makepathobject(char *path, int delim)
+{
+ int i, n;
+ char *p;
+ PyObject *v, *w;
+
+ n = 1;
+ p = path;
+ while ((p = strchr(p, delim)) != NULL) {
+ n++;
+ p++;
+ }
+ v = PyList_New(n);
+ if (v == NULL)
+ return NULL;
+ for (i = 0; ; i++) {
+ p = strchr(path, delim);
+ if (p == NULL)
+ p = strchr(path, '\0'); /* End of string */
+ w = PyString_FromStringAndSize(path, (Py_ssize_t) (p - path));
+ if (w == NULL) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ PyList_SET_ITEM(v, i, w);
+ if (*p == '\0')
+ break;
+ path = p+1;
+ }
+ return v;
+}
+
+void
+PySys_SetPath(char *path)
+{
+ PyObject *v;
+ if ((v = makepathobject(path, DELIM)) == NULL)
+ Py_FatalError("can't create sys.path");
+ if (PySys_SetObject("path", v) != 0)
+ Py_FatalError("can't assign sys.path");
+ Py_DECREF(v);
+}
+
+static PyObject *
+makeargvobject(int argc, char **argv)
+{
+ PyObject *av;
+ if (argc <= 0 || argv == NULL) {
+ /* Ensure at least one (empty) argument is seen */
+ static char *empty_argv[1] = {""};
+ argv = empty_argv;
+ argc = 1;
+ }
+ av = PyList_New(argc);
+ if (av != NULL) {
+ int i;
+ for (i = 0; i < argc; i++) {
+#ifdef __VMS
+ PyObject *v;
+
+ /* argv[0] is the script pathname if known */
+ if (i == 0) {
+ char* fn = decc$translate_vms(argv[0]);
+ if ((fn == (char *)0) || fn == (char *)-1)
+ v = PyString_FromString(argv[0]);
+ else
+ v = PyString_FromString(
+ decc$translate_vms(argv[0]));
+ } else
+ v = PyString_FromString(argv[i]);
+#else
+ PyObject *v = PyString_FromString(argv[i]);
+#endif
+ if (v == NULL) {
+ Py_DECREF(av);
+ av = NULL;
+ break;
+ }
+ PyList_SetItem(av, i, v);
+ }
+ }
+ return av;
+}
+
+void
+PySys_SetArgvEx(int argc, char **argv, int updatepath)
+{
+#if defined(HAVE_REALPATH)
+ char fullpath[MAXPATHLEN];
+#elif defined(MS_WINDOWS) && !defined(MS_WINCE)
+ char fullpath[MAX_PATH];
+#endif
+ PyObject *av = makeargvobject(argc, argv);
+ PyObject *path = PySys_GetObject("path");
+ if (av == NULL)
+ Py_FatalError("no mem for sys.argv");
+ if (PySys_SetObject("argv", av) != 0)
+ Py_FatalError("can't assign sys.argv");
+ if (updatepath && path != NULL) {
+ char *argv0 = argv[0];
+ char *p = NULL;
+ Py_ssize_t n = 0;
+ PyObject *a;
+#ifdef HAVE_READLINK
+ char link[MAXPATHLEN+1];
+ char argv0copy[2*MAXPATHLEN+1];
+ int nr = 0;
+ if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0)
+ nr = readlink(argv0, link, MAXPATHLEN);
+ if (nr > 0) {
+ /* It's a symlink */
+ link[nr] = '\0';
+ if (link[0] == SEP)
+ argv0 = link; /* Link to absolute path */
+ else if (strchr(link, SEP) == NULL)
+ ; /* Link without path */
+ else {
+ /* Must join(dirname(argv0), link) */
+ char *q = strrchr(argv0, SEP);
+ if (q == NULL)
+ argv0 = link; /* argv0 without path */
+ else {
+ /* Must make a copy */
+ strcpy(argv0copy, argv0);
+ q = strrchr(argv0copy, SEP);
+ strcpy(q+1, link);
+ argv0 = argv0copy;
+ }
+ }
+ }
+#endif /* HAVE_READLINK */
+#if SEP == '\\' /* Special case for MS filename syntax */
+ if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) {
+ char *q;
+#if defined(MS_WINDOWS) && !defined(MS_WINCE)
+ /* This code here replaces the first element in argv with the full
+ path that it represents. Under CE, there are no relative paths so
+ the argument must be the full path anyway. */
+ char *ptemp;
+ if (GetFullPathName(argv0,
+ sizeof(fullpath),
+ fullpath,
+ &ptemp)) {
+ argv0 = fullpath;
+ }
+#endif
+ p = strrchr(argv0, SEP);
+ /* Test for alternate separator */
+ q = strrchr(p ? p : argv0, '/');
+ if (q != NULL)
+ p = q;
+ if (p != NULL) {
+ n = p + 1 - argv0;
+ if (n > 1 && p[-1] != ':')
+ n--; /* Drop trailing separator */
+ }
+ }
+#else /* All other filename syntaxes */
+ if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) {
+#if defined(HAVE_REALPATH)
+ if (realpath(argv0, fullpath)) {
+ argv0 = fullpath;
+ }
+#endif
+ p = strrchr(argv0, SEP);
+ }
+ if (p != NULL) {
+#ifndef RISCOS
+ n = p + 1 - argv0;
+#else /* don't include trailing separator */
+ n = p - argv0;
+#endif /* RISCOS */
+#if SEP == '/' /* Special case for Unix filename syntax */
+ if (n > 1)
+ n--; /* Drop trailing separator */
+#endif /* Unix */
+ }
+#endif /* All others */
+ a = PyString_FromStringAndSize(argv0, n);
+ if (a == NULL)
+ Py_FatalError("no mem for sys.path insertion");
+ if (PyList_Insert(path, 0, a) < 0)
+ Py_FatalError("sys.path.insert(0) failed");
+ Py_DECREF(a);
+ }
+ Py_DECREF(av);
+}
+
+void
+PySys_SetArgv(int argc, char **argv)
+{
+ PySys_SetArgvEx(argc, argv, 0);
+}
+
+
+/* APIs to write to sys.stdout or sys.stderr using a printf-like interface.
+ Adapted from code submitted by Just van Rossum.
+
+ PySys_WriteStdout(format, ...)
+ PySys_WriteStderr(format, ...)
+
+ The first function writes to sys.stdout; the second to sys.stderr. When
+ there is a problem, they write to the real (C level) stdout or stderr;
+ no exceptions are raised.
+
+ Both take a printf-style format string as their first argument followed
+ by a variable length argument list determined by the format string.
+
+ *** WARNING ***
+
+ The format should limit the total size of the formatted output string to
+ 1000 bytes. In particular, this means that no unrestricted "%s" formats
+ should occur; these should be limited using "%.<N>s where <N> is a
+ decimal number calculated so that <N> plus the maximum size of other
+ formatted text does not exceed 1000 bytes. Also watch out for "%f",
+ which can print hundreds of digits for very large numbers.
+
+ */
+
+static void
+mywrite(char *name, FILE *fp, const char *format, va_list va)
+{
+ PyObject *file;
+ PyObject *error_type, *error_value, *error_traceback;
+
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ file = PySys_GetObject(name);
+ if (file == NULL || PyFile_AsFile(file) == fp)
+ vfprintf(fp, format, va);
+ else {
+ char buffer[1001];
+ const int written = PyOS_vsnprintf(buffer, sizeof(buffer),
+ format, va);
+ if (PyFile_WriteString(buffer, file) != 0) {
+ PyErr_Clear();
+ fputs(buffer, fp);
+ }
+ if (written < 0 || (size_t)written >= sizeof(buffer)) {
+ const char *truncated = "... truncated";
+ if (PyFile_WriteString(truncated, file) != 0) {
+ PyErr_Clear();
+ fputs(truncated, fp);
+ }
+ }
+ }
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+void
+PySys_WriteStdout(const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ mywrite("stdout", stdout, format, va);
+ va_end(va);
+}
+
+void
+PySys_WriteStderr(const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ mywrite("stderr", stderr, format, va);
+ va_end(va);
+}
diff --git a/contrib/tools/python/src/Python/thread.c b/contrib/tools/python/src/Python/thread.c
new file mode 100644
index 0000000000..aa4190cb08
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread.c
@@ -0,0 +1,421 @@
+
+/* Thread package.
+ This is intended to be usable independently from Python.
+ The implementation for system foobar is in a file thread_foobar.h
+ which is included by this file dependent on config settings.
+ Stuff shared by all thread_*.h files is collected here. */
+
+#include "Python.h"
+
+
+#ifndef _POSIX_THREADS
+/* This means pthreads are not implemented in libc headers, hence the macro
+ not present in unistd.h. But they still can be implemented as an external
+ library (e.g. gnu pth in pthread emulation) */
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h> /* _POSIX_THREADS */
+# endif
+#endif
+
+#ifndef DONT_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef __sgi
+#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */
+#undef _POSIX_THREADS
+#endif
+#endif
+
+#include "pythread.h"
+
+#ifndef _POSIX_THREADS
+
+#ifdef __sgi
+#define SGI_THREADS
+#endif
+
+#ifdef HAVE_THREAD_H
+#define SOLARIS_THREADS
+#endif
+
+#if defined(sun) && !defined(SOLARIS_THREADS)
+#define SUN_LWP
+#endif
+
+/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
+ enough of the Posix threads package is implemented to support python
+ threads.
+
+ This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
+ a check of __ia64 to verify that we're running on an ia64 system instead
+ of a pa-risc system.
+*/
+#ifdef __hpux
+#ifdef _SC_THREADS
+#define _POSIX_THREADS
+#endif
+#endif
+
+#endif /* _POSIX_THREADS */
+
+
+#ifdef Py_DEBUG
+static int thread_debug = 0;
+#define dprintf(args) (void)((thread_debug & 1) && printf args)
+#define d2printf(args) ((thread_debug & 8) && printf args)
+#else
+#define dprintf(args)
+#define d2printf(args)
+#endif
+
+static int initialized;
+
+static void PyThread__init_thread(void); /* Forward */
+
+void
+PyThread_init_thread(void)
+{
+#ifdef Py_DEBUG
+ char *p = Py_GETENV("PYTHONTHREADDEBUG");
+
+ if (p) {
+ if (*p)
+ thread_debug = atoi(p);
+ else
+ thread_debug = 1;
+ }
+#endif /* Py_DEBUG */
+ if (initialized)
+ return;
+ initialized = 1;
+ dprintf(("PyThread_init_thread called\n"));
+ PyThread__init_thread();
+}
+
+/* Support for runtime thread stack size tuning.
+ A value of 0 means using the platform's default stack size
+ or the size specified by the THREAD_STACK_SIZE macro. */
+static size_t _pythread_stacksize = 0;
+
+#ifdef SGI_THREADS
+#include "thread_sgi.h"
+#endif
+
+#ifdef SOLARIS_THREADS
+#error #include "thread_solaris.h"
+#endif
+
+#ifdef SUN_LWP
+#include "thread_lwp.h"
+#endif
+
+#ifdef HAVE_PTH
+#include "thread_pth.h"
+#undef _POSIX_THREADS
+#endif
+
+#ifdef _POSIX_THREADS
+#include "thread_pthread.h"
+#endif
+
+#ifdef C_THREADS
+#include "thread_cthread.h"
+#endif
+
+#ifdef NT_THREADS
+#include "thread_nt.h"
+#endif
+
+#ifdef OS2_THREADS
+#include "thread_os2.h"
+#endif
+
+#ifdef BEOS_THREADS
+#include "thread_beos.h"
+#endif
+
+#ifdef PLAN9_THREADS
+#include "thread_plan9.h"
+#endif
+
+#ifdef ATHEOS_THREADS
+#include "thread_atheos.h"
+#endif
+
+/*
+#ifdef FOOBAR_THREADS
+#include "thread_foobar.h"
+#endif
+*/
+
+/* return the current thread stack size */
+size_t
+PyThread_get_stacksize(void)
+{
+ return _pythread_stacksize;
+}
+
+/* Only platforms defining a THREAD_SET_STACKSIZE() macro
+ in thread_<platform>.h support changing the stack size.
+ Return 0 if stack size is valid,
+ -1 if stack size value is invalid,
+ -2 if setting stack size is not supported. */
+int
+PyThread_set_stacksize(size_t size)
+{
+#if defined(THREAD_SET_STACKSIZE)
+ return THREAD_SET_STACKSIZE(size);
+#else
+ return -2;
+#endif
+}
+
+#ifndef Py_HAVE_NATIVE_TLS
+/* If the platform has not supplied a platform specific
+ TLS implementation, provide our own.
+
+ This code stolen from "thread_sgi.h", where it was the only
+ implementation of an existing Python TLS API.
+*/
+/* ------------------------------------------------------------------------
+Per-thread data ("key") support.
+
+Use PyThread_create_key() to create a new key. This is typically shared
+across threads.
+
+Use PyThread_set_key_value(thekey, value) to associate void* value with
+thekey in the current thread. Each thread has a distinct mapping of thekey
+to a void* value. Caution: if the current thread already has a mapping
+for thekey, value is ignored.
+
+Use PyThread_get_key_value(thekey) to retrieve the void* value associated
+with thekey in the current thread. This returns NULL if no value is
+associated with thekey in the current thread.
+
+Use PyThread_delete_key_value(thekey) to forget the current thread's associated
+value for thekey. PyThread_delete_key(thekey) forgets the values associated
+with thekey across *all* threads.
+
+While some of these functions have error-return values, none set any
+Python exception.
+
+None of the functions does memory management on behalf of the void* values.
+You need to allocate and deallocate them yourself. If the void* values
+happen to be PyObject*, these functions don't do refcount operations on
+them either.
+
+The GIL does not need to be held when calling these functions; they supply
+their own locking. This isn't true of PyThread_create_key(), though (see
+next paragraph).
+
+There's a hidden assumption that PyThread_create_key() will be called before
+any of the other functions are called. There's also a hidden assumption
+that calls to PyThread_create_key() are serialized externally.
+------------------------------------------------------------------------ */
+
+/* A singly-linked list of struct key objects remembers all the key->value
+ * associations. File static keyhead heads the list. keymutex is used
+ * to enforce exclusion internally.
+ */
+struct key {
+ /* Next record in the list, or NULL if this is the last record. */
+ struct key *next;
+
+ /* The thread id, according to PyThread_get_thread_ident(). */
+ long id;
+
+ /* The key and its associated value. */
+ int key;
+ void *value;
+};
+
+static struct key *keyhead = NULL;
+static PyThread_type_lock keymutex = NULL;
+static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */
+
+/* Internal helper.
+ * If the current thread has a mapping for key, the appropriate struct key*
+ * is returned. NB: value is ignored in this case!
+ * If there is no mapping for key in the current thread, then:
+ * If value is NULL, NULL is returned.
+ * Else a mapping of key to value is created for the current thread,
+ * and a pointer to a new struct key* is returned; except that if
+ * malloc() can't find room for a new struct key*, NULL is returned.
+ * So when value==NULL, this acts like a pure lookup routine, and when
+ * value!=NULL, this acts like dict.setdefault(), returning an existing
+ * mapping if one exists, else creating a new mapping.
+ *
+ * Caution: this used to be too clever, trying to hold keymutex only
+ * around the "p->next = keyhead; keyhead = p" pair. That allowed
+ * another thread to mutate the list, via key deletion, concurrent with
+ * find_key() crawling over the list. Hilarity ensued. For example, when
+ * the for-loop here does "p = p->next", p could end up pointing at a
+ * record that PyThread_delete_key_value() was concurrently free()'ing.
+ * That could lead to anything, from failing to find a key that exists, to
+ * segfaults. Now we lock the whole routine.
+ */
+static struct key *
+find_key(int key, void *value)
+{
+ struct key *p, *prev_p;
+ long id = PyThread_get_thread_ident();
+
+ if (!keymutex)
+ return NULL;
+ PyThread_acquire_lock(keymutex, 1);
+ prev_p = NULL;
+ for (p = keyhead; p != NULL; p = p->next) {
+ if (p->id == id && p->key == key)
+ goto Done;
+ /* Sanity check. These states should never happen but if
+ * they do we must abort. Otherwise we'll end up spinning
+ * in a tight loop with the lock held. A similar check is done
+ * in pystate.c tstate_delete_common(). */
+ if (p == prev_p)
+ Py_FatalError("tls find_key: small circular list(!)");
+ prev_p = p;
+ if (p->next == keyhead)
+ Py_FatalError("tls find_key: circular list(!)");
+ }
+ if (value == NULL) {
+ assert(p == NULL);
+ goto Done;
+ }
+ p = (struct key *)malloc(sizeof(struct key));
+ if (p != NULL) {
+ p->id = id;
+ p->key = key;
+ p->value = value;
+ p->next = keyhead;
+ keyhead = p;
+ }
+ Done:
+ PyThread_release_lock(keymutex);
+ return p;
+}
+
+/* Return a new key. This must be called before any other functions in
+ * this family, and callers must arrange to serialize calls to this
+ * function. No violations are detected.
+ */
+int
+PyThread_create_key(void)
+{
+ /* All parts of this function are wrong if it's called by multiple
+ * threads simultaneously.
+ */
+ if (keymutex == NULL)
+ keymutex = PyThread_allocate_lock();
+ return ++nkeys;
+}
+
+/* Forget the associations for key across *all* threads. */
+void
+PyThread_delete_key(int key)
+{
+ struct key *p, **q;
+
+ PyThread_acquire_lock(keymutex, 1);
+ q = &keyhead;
+ while ((p = *q) != NULL) {
+ if (p->key == key) {
+ *q = p->next;
+ free((void *)p);
+ /* NB This does *not* free p->value! */
+ }
+ else
+ q = &p->next;
+ }
+ PyThread_release_lock(keymutex);
+}
+
+/* Confusing: If the current thread has an association for key,
+ * value is ignored, and 0 is returned. Else an attempt is made to create
+ * an association of key to value for the current thread. 0 is returned
+ * if that succeeds, but -1 is returned if there's not enough memory
+ * to create the association. value must not be NULL.
+ */
+int
+PyThread_set_key_value(int key, void *value)
+{
+ struct key *p;
+
+ assert(value != NULL);
+ p = find_key(key, value);
+ if (p == NULL)
+ return -1;
+ else
+ return 0;
+}
+
+/* Retrieve the value associated with key in the current thread, or NULL
+ * if the current thread doesn't have an association for key.
+ */
+void *
+PyThread_get_key_value(int key)
+{
+ struct key *p = find_key(key, NULL);
+
+ if (p == NULL)
+ return NULL;
+ else
+ return p->value;
+}
+
+/* Forget the current thread's association for key, if any. */
+void
+PyThread_delete_key_value(int key)
+{
+ long id = PyThread_get_thread_ident();
+ struct key *p, **q;
+
+ PyThread_acquire_lock(keymutex, 1);
+ q = &keyhead;
+ while ((p = *q) != NULL) {
+ if (p->key == key && p->id == id) {
+ *q = p->next;
+ free((void *)p);
+ /* NB This does *not* free p->value! */
+ break;
+ }
+ else
+ q = &p->next;
+ }
+ PyThread_release_lock(keymutex);
+}
+
+/* Forget everything not associated with the current thread id.
+ * This function is called from PyOS_AfterFork(). It is necessary
+ * because other thread ids which were in use at the time of the fork
+ * may be reused for new threads created in the forked process.
+ */
+void
+PyThread_ReInitTLS(void)
+{
+ long id = PyThread_get_thread_ident();
+ struct key *p, **q;
+
+ if (!keymutex)
+ return;
+
+ /* As with interpreter_lock in PyEval_ReInitThreads()
+ we just create a new lock without freeing the old one */
+ keymutex = PyThread_allocate_lock();
+
+ /* Delete all keys which do not match the current thread id */
+ q = &keyhead;
+ while ((p = *q) != NULL) {
+ if (p->id != id) {
+ *q = p->next;
+ free((void *)p);
+ /* NB This does *not* free p->value! */
+ }
+ else
+ q = &p->next;
+ }
+}
+
+#endif /* Py_HAVE_NATIVE_TLS */
diff --git a/contrib/tools/python/src/Python/thread_atheos.h b/contrib/tools/python/src/Python/thread_atheos.h
new file mode 100644
index 0000000000..230594f144
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_atheos.h
@@ -0,0 +1,259 @@
+/* Threading for AtheOS.
+ Based on thread_beos.h. */
+
+#include <atheos/threads.h>
+#include <atheos/semaphore.h>
+#include <atheos/atomic.h>
+#include <errno.h>
+#include <string.h>
+
+/* Missing decl from threads.h */
+extern int exit_thread(int);
+
+
+/* Undefine FASTLOCK to play with simple semaphores. */
+#define FASTLOCK
+
+
+#ifdef FASTLOCK
+
+/* Use an atomic counter and a semaphore for maximum speed. */
+typedef struct fastmutex {
+ sem_id sem;
+ atomic_t count;
+} fastmutex_t;
+
+
+static int fastmutex_create(const char *name, fastmutex_t * mutex);
+static int fastmutex_destroy(fastmutex_t * mutex);
+static int fastmutex_lock(fastmutex_t * mutex);
+static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout);
+static int fastmutex_unlock(fastmutex_t * mutex);
+
+
+static int fastmutex_create(const char *name, fastmutex_t * mutex)
+{
+ mutex->count = 0;
+ mutex->sem = create_semaphore(name, 0, 0);
+ return (mutex->sem < 0) ? -1 : 0;
+}
+
+
+static int fastmutex_destroy(fastmutex_t * mutex)
+{
+ if (fastmutex_timedlock(mutex, 0) == 0 || errno == EWOULDBLOCK) {
+ return delete_semaphore(mutex->sem);
+ }
+ return 0;
+}
+
+
+static int fastmutex_lock(fastmutex_t * mutex)
+{
+ atomic_t prev = atomic_add(&mutex->count, 1);
+ if (prev > 0)
+ return lock_semaphore(mutex->sem);
+ return 0;
+}
+
+
+static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout)
+{
+ atomic_t prev = atomic_add(&mutex->count, 1);
+ if (prev > 0)
+ return lock_semaphore_x(mutex->sem, 1, 0, timeout);
+ return 0;
+}
+
+
+static int fastmutex_unlock(fastmutex_t * mutex)
+{
+ atomic_t prev = atomic_add(&mutex->count, -1);
+ if (prev > 1)
+ return unlock_semaphore(mutex->sem);
+ return 0;
+}
+
+
+#endif /* FASTLOCK */
+
+
+/*
+ * Initialization.
+ *
+ */
+static void PyThread__init_thread(void)
+{
+ /* Do nothing. */
+ return;
+}
+
+
+/*
+ * Thread support.
+ *
+ */
+
+static atomic_t thread_count = 0;
+
+long PyThread_start_new_thread(void (*func) (void *), void *arg)
+{
+ status_t success = -1;
+ thread_id tid;
+ char name[OS_NAME_LENGTH];
+ atomic_t this_thread;
+
+ dprintf(("PyThread_start_new_thread called\n"));
+
+ this_thread = atomic_add(&thread_count, 1);
+ PyOS_snprintf(name, sizeof(name), "python thread (%d)", this_thread);
+
+ tid = spawn_thread(name, func, NORMAL_PRIORITY, 0, arg);
+ if (tid < 0) {
+ dprintf(("PyThread_start_new_thread spawn_thread failed: %s\n", strerror(errno)));
+ } else {
+ success = resume_thread(tid);
+ if (success < 0) {
+ dprintf(("PyThread_start_new_thread resume_thread failed: %s\n", strerror(errno)));
+ }
+ }
+
+ return (success < 0 ? -1 : tid);
+}
+
+
+long PyThread_get_thread_ident(void)
+{
+ return get_thread_id(NULL);
+}
+
+
+void PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+
+ /* Thread-safe way to read a variable without a mutex: */
+ if (atomic_add(&thread_count, 0) == 0) {
+ /* No threads around, so exit main(). */
+ exit(0);
+ } else {
+ /* We're a thread */
+ exit_thread(0);
+ }
+}
+
+
+/*
+ * Lock support.
+ *
+ */
+
+static atomic_t lock_count = 0;
+
+PyThread_type_lock PyThread_allocate_lock(void)
+{
+#ifdef FASTLOCK
+ fastmutex_t *lock;
+#else
+ sem_id sema;
+#endif
+ char name[OS_NAME_LENGTH];
+ atomic_t this_lock;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+
+#ifdef FASTLOCK
+ lock = (fastmutex_t *) malloc(sizeof(fastmutex_t));
+ if (lock == NULL) {
+ dprintf(("PyThread_allocate_lock failed: out of memory\n"));
+ return (PyThread_type_lock) NULL;
+ }
+#endif
+ this_lock = atomic_add(&lock_count, 1);
+ PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock);
+
+#ifdef FASTLOCK
+ if (fastmutex_create(name, lock) < 0) {
+ dprintf(("PyThread_allocate_lock failed: %s\n",
+ strerror(errno)));
+ free(lock);
+ lock = NULL;
+ }
+ dprintf(("PyThread_allocate_lock()-> %p\n", lock));
+ return (PyThread_type_lock) lock;
+#else
+ sema = create_semaphore(name, 1, 0);
+ if (sema < 0) {
+ dprintf(("PyThread_allocate_lock failed: %s\n",
+ strerror(errno)));
+ sema = 0;
+ }
+ dprintf(("PyThread_allocate_lock()-> %p\n", sema));
+ return (PyThread_type_lock) sema;
+#endif
+}
+
+
+void PyThread_free_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+
+#ifdef FASTLOCK
+ if (fastmutex_destroy((fastmutex_t *) lock) < 0) {
+ dprintf(("PyThread_free_lock(%p) failed: %s\n", lock,
+ strerror(errno)));
+ }
+ free(lock);
+#else
+ if (delete_semaphore((sem_id) lock) < 0) {
+ dprintf(("PyThread_free_lock(%p) failed: %s\n", lock,
+ strerror(errno)));
+ }
+#endif
+}
+
+
+int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int retval;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock,
+ waitflag));
+
+#ifdef FASTLOCK
+ if (waitflag)
+ retval = fastmutex_lock((fastmutex_t *) lock);
+ else
+ retval = fastmutex_timedlock((fastmutex_t *) lock, 0);
+#else
+ if (waitflag)
+ retval = lock_semaphore((sem_id) lock);
+ else
+ retval = lock_semaphore_x((sem_id) lock, 1, 0, 0);
+#endif
+ if (retval < 0) {
+ dprintf(("PyThread_acquire_lock(%p, %d) failed: %s\n",
+ lock, waitflag, strerror(errno)));
+ }
+ dprintf(("PyThread_acquire_lock(%p, %d)-> %d\n", lock, waitflag,
+ retval));
+ return retval < 0 ? 0 : 1;
+}
+
+
+void PyThread_release_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+
+#ifdef FASTLOCK
+ if (fastmutex_unlock((fastmutex_t *) lock) < 0) {
+ dprintf(("PyThread_release_lock(%p) failed: %s\n", lock,
+ strerror(errno)));
+ }
+#else
+ if (unlock_semaphore((sem_id) lock) < 0) {
+ dprintf(("PyThread_release_lock(%p) failed: %s\n", lock,
+ strerror(errno)));
+ }
+#endif
+}
diff --git a/contrib/tools/python/src/Python/thread_beos.h b/contrib/tools/python/src/Python/thread_beos.h
new file mode 100644
index 0000000000..65dc470bcd
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_beos.h
@@ -0,0 +1,248 @@
+#include <kernel/OS.h>
+#include <support/SupportDefs.h>
+#include <errno.h>
+
+/* ----------------------------------------------------------------------
+ * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
+ * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
+ */
+typedef struct benaphore {
+ sem_id _sem;
+ int32 _atom;
+} benaphore_t;
+
+static status_t benaphore_create( const char *name, benaphore_t *ben );
+static status_t benaphore_destroy( benaphore_t *ben );
+static status_t benaphore_lock( benaphore_t *ben );
+static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
+static status_t benaphore_unlock( benaphore_t *ben );
+
+static status_t benaphore_create( const char *name, benaphore_t *ben )
+{
+ if( ben != NULL ) {
+ ben->_atom = 0;
+ ben->_sem = create_sem( 0, name );
+
+ if( ben->_sem < B_NO_ERROR ) {
+ return B_BAD_SEM_ID;
+ }
+ } else {
+ return EFAULT;
+ }
+
+ return EOK;
+}
+
+static status_t benaphore_destroy( benaphore_t *ben )
+{
+ if( ben->_sem >= B_NO_ERROR ) {
+ status_t retval = benaphore_timedlock( ben, 0 );
+
+ if( retval == EOK || retval == EWOULDBLOCK ) {
+ status_t del_retval = delete_sem( ben->_sem );
+
+ return del_retval;
+ }
+ }
+
+ return B_BAD_SEM_ID;
+}
+
+static status_t benaphore_lock( benaphore_t *ben )
+{
+ int32 prev = atomic_add( &(ben->_atom), 1 );
+
+ if( prev > 0 ) {
+ return acquire_sem( ben->_sem );
+ }
+
+ return EOK;
+}
+
+static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
+{
+ int32 prev = atomic_add( &(ben->_atom), 1 );
+
+ if( prev > 0 ) {
+ status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
+
+ switch( retval ) {
+ case B_WOULD_BLOCK: /* Fall through... */
+ case B_TIMED_OUT:
+ return EWOULDBLOCK;
+ break;
+ case B_OK:
+ return EOK;
+ break;
+ default:
+ return retval;
+ break;
+ }
+ }
+
+ return EOK;
+}
+
+static status_t benaphore_unlock( benaphore_t *ben )
+{
+ int32 prev = atomic_add( &(ben->_atom), -1 );
+
+ if( prev > 1 ) {
+ return release_sem( ben->_sem );
+ }
+
+ return EOK;
+}
+
+/* ----------------------------------------------------------------------
+ * Initialization.
+ */
+static void PyThread__init_thread( void )
+{
+ /* Do nothing. */
+ return;
+}
+
+/* ----------------------------------------------------------------------
+ * Thread support.
+ *
+ * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
+ * and there's no legacy thread module to support.
+ */
+
+static int32 thread_count = 0;
+
+long PyThread_start_new_thread( void (*func)(void *), void *arg )
+{
+ status_t success = 0;
+ thread_id tid;
+ char name[B_OS_NAME_LENGTH];
+ int32 this_thread;
+
+ dprintf(("PyThread_start_new_thread called\n"));
+
+ /* We are so very thread-safe... */
+ this_thread = atomic_add( &thread_count, 1 );
+ PyOS_snprintf(name, sizeof(name),
+ "python thread (%d)", this_thread );
+
+ tid = spawn_thread( (thread_func)func, name,
+ B_NORMAL_PRIORITY, arg );
+ if( tid > B_NO_ERROR ) {
+ success = resume_thread( tid );
+ }
+
+ return ( success == B_NO_ERROR ? tid : -1 );
+}
+
+long PyThread_get_thread_ident( void )
+{
+ /* Presumed to return the current thread's ID... */
+ thread_id tid;
+ tid = find_thread( NULL );
+
+ return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
+}
+
+void PyThread_exit_thread( void )
+{
+ int32 threads;
+
+ dprintf(("PyThread_exit_thread called\n"));
+
+ /* Thread-safe way to read a variable without a mutex: */
+ threads = atomic_add( &thread_count, 0 );
+
+ if( threads == 0 ) {
+ /* No threads around, so exit main(). */
+ exit(0);
+ } else {
+ /* Oh, we're a thread, let's try to exit gracefully... */
+ exit_thread( B_NO_ERROR );
+ }
+}
+
+/* ----------------------------------------------------------------------
+ * Lock support.
+ */
+
+static int32 lock_count = 0;
+
+PyThread_type_lock PyThread_allocate_lock( void )
+{
+ benaphore_t *lock;
+ status_t retval;
+ char name[B_OS_NAME_LENGTH];
+ int32 this_lock;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+
+ lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
+ if( lock == NULL ) {
+ /* TODO: that's bad, raise MemoryError */
+ return (PyThread_type_lock)NULL;
+ }
+
+ this_lock = atomic_add( &lock_count, 1 );
+ PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock);
+
+ retval = benaphore_create( name, lock );
+ if( retval != EOK ) {
+ /* TODO: that's bad, raise an exception */
+ return (PyThread_type_lock)NULL;
+ }
+
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void PyThread_free_lock( PyThread_type_lock lock )
+{
+ status_t retval;
+
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+
+ retval = benaphore_destroy( (benaphore_t *)lock );
+ if( retval != EOK ) {
+ /* TODO: that's bad, raise an exception */
+ return;
+ }
+}
+
+int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
+{
+ int success;
+ status_t retval;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+
+ if( waitflag ) {
+ retval = benaphore_lock( (benaphore_t *)lock );
+ } else {
+ retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
+ }
+
+ if( retval == EOK ) {
+ success = 1;
+ } else {
+ success = 0;
+
+ /* TODO: that's bad, raise an exception */
+ }
+
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void PyThread_release_lock( PyThread_type_lock lock )
+{
+ status_t retval;
+
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+
+ retval = benaphore_unlock( (benaphore_t *)lock );
+ if( retval != EOK ) {
+ /* TODO: that's bad, raise an exception */
+ return;
+ }
+}
diff --git a/contrib/tools/python/src/Python/thread_cthread.h b/contrib/tools/python/src/Python/thread_cthread.h
new file mode 100644
index 0000000000..1b3e3904cd
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_cthread.h
@@ -0,0 +1,112 @@
+
+#ifdef MACH_C_THREADS
+#include <mach/cthreads.h>
+#endif
+
+#ifdef HURD_C_THREADS
+#include <cthreads.h>
+#endif
+
+/*
+ * Initialization.
+ */
+static void
+PyThread__init_thread(void)
+{
+#ifndef HURD_C_THREADS
+ /* Roland McGrath said this should not be used since this is
+ done while linking to threads */
+ cthread_init();
+#else
+/* do nothing */
+ ;
+#endif
+}
+
+/*
+ * Thread support.
+ */
+long
+PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ int success = 0; /* init not needed when SOLARIS_THREADS and */
+ /* C_THREADS implemented properly */
+
+ dprintf(("PyThread_start_new_thread called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+ /* looks like solaris detaches the thread to never rejoin
+ * so well do it here
+ */
+ cthread_detach(cthread_fork((cthread_fn_t) func, arg));
+ return success < 0 ? -1 : 0;
+}
+
+long
+PyThread_get_thread_ident(void)
+{
+ if (!initialized)
+ PyThread_init_thread();
+ return (long) cthread_self();
+}
+
+void
+PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+ if (!initialized)
+ exit(0);
+ cthread_exit(0);
+}
+
+/*
+ * Lock support.
+ */
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+ mutex_t lock;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock = mutex_alloc();
+ if (mutex_init(lock)) {
+ perror("mutex_init");
+ free((void *) lock);
+ lock = 0;
+ }
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void
+PyThread_free_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+ mutex_free(lock);
+}
+
+int
+PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success = FALSE;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+ if (waitflag) { /* blocking */
+ mutex_lock((mutex_t)lock);
+ success = TRUE;
+ } else { /* non blocking */
+ success = mutex_try_lock((mutex_t)lock);
+ }
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void
+PyThread_release_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+ mutex_unlock((mutex_t )lock);
+}
diff --git a/contrib/tools/python/src/Python/thread_lwp.h b/contrib/tools/python/src/Python/thread_lwp.h
new file mode 100644
index 0000000000..ba7b37ad7e
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_lwp.h
@@ -0,0 +1,113 @@
+
+#include <stdlib.h>
+#include <lwp/lwp.h>
+#include <lwp/stackdep.h>
+
+#define STACKSIZE 1000 /* stacksize for a thread */
+#define NSTACKS 2 /* # stacks to be put in cache initially */
+
+struct lock {
+ int lock_locked;
+ cv_t lock_condvar;
+ mon_t lock_monitor;
+};
+
+
+/*
+ * Initialization.
+ */
+static void PyThread__init_thread(void)
+{
+ lwp_setstkcache(STACKSIZE, NSTACKS);
+}
+
+/*
+ * Thread support.
+ */
+
+
+long PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ thread_t tid;
+ int success;
+ dprintf(("PyThread_start_new_thread called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+ success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
+ return success < 0 ? -1 : 0;
+}
+
+long PyThread_get_thread_ident(void)
+{
+ thread_t tid;
+ if (!initialized)
+ PyThread_init_thread();
+ if (lwp_self(&tid) < 0)
+ return -1;
+ return tid.thread_id;
+}
+
+void PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+ if (!initialized)
+ exit(0);
+ lwp_destroy(SELF);
+}
+
+/*
+ * Lock support.
+ */
+PyThread_type_lock PyThread_allocate_lock(void)
+{
+ struct lock *lock;
+ extern char *malloc(size_t);
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock = (struct lock *) malloc(sizeof(struct lock));
+ lock->lock_locked = 0;
+ (void) mon_create(&lock->lock_monitor);
+ (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void PyThread_free_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+ mon_destroy(((struct lock *) lock)->lock_monitor);
+ free((char *) lock);
+}
+
+int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+ success = 0;
+
+ (void) mon_enter(((struct lock *) lock)->lock_monitor);
+ if (waitflag)
+ while (((struct lock *) lock)->lock_locked)
+ cv_wait(((struct lock *) lock)->lock_condvar);
+ if (!((struct lock *) lock)->lock_locked) {
+ success = 1;
+ ((struct lock *) lock)->lock_locked = 1;
+ }
+ cv_broadcast(((struct lock *) lock)->lock_condvar);
+ mon_exit(((struct lock *) lock)->lock_monitor);
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void PyThread_release_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+ (void) mon_enter(((struct lock *) lock)->lock_monitor);
+ ((struct lock *) lock)->lock_locked = 0;
+ cv_broadcast(((struct lock *) lock)->lock_condvar);
+ mon_exit(((struct lock *) lock)->lock_monitor);
+}
diff --git a/contrib/tools/python/src/Python/thread_nt.h b/contrib/tools/python/src/Python/thread_nt.h
new file mode 100644
index 0000000000..a161d7cb46
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_nt.h
@@ -0,0 +1,359 @@
+
+/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
+/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
+/* Eliminated some memory leaks, gsw@agere.com */
+
+#include <windows.h>
+#include <limits.h>
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+typedef struct NRMUTEX {
+ LONG owned ;
+ DWORD thread_id ;
+ HANDLE hevent ;
+} NRMUTEX, *PNRMUTEX ;
+
+
+BOOL
+InitializeNonRecursiveMutex(PNRMUTEX mutex)
+{
+ mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
+ mutex->thread_id = 0 ;
+ mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
+ return mutex->hevent != NULL ; /* TRUE if the mutex is created */
+}
+
+VOID
+DeleteNonRecursiveMutex(PNRMUTEX mutex)
+{
+ /* No in-use check */
+ CloseHandle(mutex->hevent) ;
+ mutex->hevent = NULL ; /* Just in case */
+}
+
+DWORD
+EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
+{
+ /* Assume that the thread waits successfully */
+ DWORD ret ;
+
+ /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
+ if (!wait)
+ {
+ if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)
+ return WAIT_TIMEOUT ;
+ ret = WAIT_OBJECT_0 ;
+ }
+ else
+ ret = InterlockedIncrement(&mutex->owned) ?
+ /* Some thread owns the mutex, let's wait... */
+ WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
+
+ mutex->thread_id = GetCurrentThreadId() ; /* We own it */
+ return ret ;
+}
+
+BOOL
+LeaveNonRecursiveMutex(PNRMUTEX mutex)
+{
+ /* We don't own the mutex */
+ mutex->thread_id = 0 ;
+ return
+ InterlockedDecrement(&mutex->owned) < 0 ||
+ SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
+}
+
+PNRMUTEX
+AllocNonRecursiveMutex(void)
+{
+ PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
+ if (mutex && !InitializeNonRecursiveMutex(mutex))
+ {
+ free(mutex) ;
+ mutex = NULL ;
+ }
+ return mutex ;
+}
+
+void
+FreeNonRecursiveMutex(PNRMUTEX mutex)
+{
+ if (mutex)
+ {
+ DeleteNonRecursiveMutex(mutex) ;
+ free(mutex) ;
+ }
+}
+
+long PyThread_get_thread_ident(void);
+
+/*
+ * Initialization of the C package, should not be needed.
+ */
+static void
+PyThread__init_thread(void)
+{
+}
+
+/*
+ * Thread support.
+ */
+
+typedef struct {
+ void (*func)(void*);
+ void *arg;
+} callobj;
+
+/* thunker to call adapt between the function type used by the system's
+thread start function and the internally used one. */
+#if defined(MS_WINCE)
+static DWORD WINAPI
+#else
+static unsigned __stdcall
+#endif
+bootstrap(void *call)
+{
+ callobj *obj = (callobj*)call;
+ void (*func)(void*) = obj->func;
+ void *arg = obj->arg;
+ HeapFree(GetProcessHeap(), 0, obj);
+ func(arg);
+ return 0;
+}
+
+long
+PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ HANDLE hThread;
+ unsigned threadID;
+ callobj *obj;
+
+ dprintf(("%ld: PyThread_start_new_thread called\n",
+ PyThread_get_thread_ident()));
+ if (!initialized)
+ PyThread_init_thread();
+
+ obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+ if (!obj)
+ return -1;
+ obj->func = func;
+ obj->arg = arg;
+#if defined(MS_WINCE)
+ hThread = CreateThread(NULL,
+ Py_SAFE_DOWNCAST(_pythread_stacksize, Py_ssize_t, SIZE_T),
+ bootstrap, obj, 0, &threadID);
+#else
+ hThread = (HANDLE)_beginthreadex(0,
+ Py_SAFE_DOWNCAST(_pythread_stacksize,
+ Py_ssize_t, unsigned int),
+ bootstrap, obj,
+ 0, &threadID);
+#endif
+ if (hThread == 0) {
+#if defined(MS_WINCE)
+ /* Save error in variable, to prevent PyThread_get_thread_ident
+ from clobbering it. */
+ unsigned e = GetLastError();
+ dprintf(("%ld: PyThread_start_new_thread failed, win32 error code %u\n",
+ PyThread_get_thread_ident(), e));
+#else
+ /* I've seen errno == EAGAIN here, which means "there are
+ * too many threads".
+ */
+ int e = errno;
+ dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",
+ PyThread_get_thread_ident(), e));
+#endif
+ threadID = (unsigned)-1;
+ HeapFree(GetProcessHeap(), 0, obj);
+ }
+ else {
+ dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
+ PyThread_get_thread_ident(), (void*)hThread));
+ CloseHandle(hThread);
+ }
+ return (long) threadID;
+}
+
+/*
+ * Return the thread Id instead of a handle. The Id is said to uniquely identify the
+ * thread in the system
+ */
+long
+PyThread_get_thread_ident(void)
+{
+ if (!initialized)
+ PyThread_init_thread();
+
+ return GetCurrentThreadId();
+}
+
+void
+PyThread_exit_thread(void)
+{
+ dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
+ if (!initialized)
+ exit(0);
+#if defined(MS_WINCE)
+ ExitThread(0);
+#else
+ _endthreadex(0);
+#endif
+}
+
+/*
+ * Lock support. It has too be implemented as semaphores.
+ * I [Dag] tried to implement it with mutex but I could find a way to
+ * tell whether a thread already own the lock or not.
+ */
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+ PNRMUTEX aLock;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ aLock = AllocNonRecursiveMutex() ;
+
+ dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
+
+ return (PyThread_type_lock) aLock;
+}
+
+void
+PyThread_free_lock(PyThread_type_lock aLock)
+{
+ dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
+
+ FreeNonRecursiveMutex(aLock) ;
+}
+
+/*
+ * Return 1 on success if the lock was acquired
+ *
+ * and 0 if the lock was not acquired. This means a 0 is returned
+ * if the lock has already been acquired by this thread!
+ */
+int
+PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
+{
+ int success ;
+
+ dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
+
+ success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
+
+ dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
+
+ return success;
+}
+
+void
+PyThread_release_lock(PyThread_type_lock aLock)
+{
+ dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
+
+ if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
+ dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock, GetLastError()));
+}
+
+/* minimum/maximum thread stack sizes supported */
+#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
+#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
+
+/* set the thread stack size.
+ * Return 0 if size is valid, -1 otherwise.
+ */
+static int
+_pythread_nt_set_stacksize(size_t size)
+{
+ /* set to default */
+ if (size == 0) {
+ _pythread_stacksize = 0;
+ return 0;
+ }
+
+ /* valid range? */
+ if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
+ _pythread_stacksize = size;
+ return 0;
+ }
+
+ return -1;
+}
+
+#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)
+
+
+/* use native Windows TLS functions */
+#define Py_HAVE_NATIVE_TLS
+
+#ifdef Py_HAVE_NATIVE_TLS
+int
+PyThread_create_key(void)
+{
+ return (int) TlsAlloc();
+}
+
+void
+PyThread_delete_key(int key)
+{
+ TlsFree(key);
+}
+
+/* We must be careful to emulate the strange semantics implemented in thread.c,
+ * where the value is only set if it hasn't been set before.
+ */
+int
+PyThread_set_key_value(int key, void *value)
+{
+ BOOL ok;
+ void *oldvalue;
+
+ assert(value != NULL);
+ oldvalue = TlsGetValue(key);
+ if (oldvalue != NULL)
+ /* ignore value if already set */
+ return 0;
+ ok = TlsSetValue(key, value);
+ if (!ok)
+ return -1;
+ return 0;
+}
+
+void *
+PyThread_get_key_value(int key)
+{
+ /* because TLS is used in the Py_END_ALLOW_THREAD macro,
+ * it is necessary to preserve the windows error state, because
+ * it is assumed to be preserved across the call to the macro.
+ * Ideally, the macro should be fixed, but it is simpler to
+ * do it here.
+ */
+ DWORD error = GetLastError();
+ void *result = TlsGetValue(key);
+ SetLastError(error);
+ return result;
+}
+
+void
+PyThread_delete_key_value(int key)
+{
+ /* NULL is used as "key missing", and it is also the default
+ * given by TlsGetValue() if nothing has been set yet.
+ */
+ TlsSetValue(key, NULL);
+}
+
+/* reinitialization of TLS is not necessary after fork when using
+ * the native TLS functions. And forking isn't supported on Windows either.
+ */
+void
+PyThread_ReInitTLS(void)
+{}
+
+#endif
diff --git a/contrib/tools/python/src/Python/thread_os2.h b/contrib/tools/python/src/Python/thread_os2.h
new file mode 100644
index 0000000000..1b264b5ad5
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_os2.h
@@ -0,0 +1,267 @@
+/* This code implemented by cvale@netcom.com */
+
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#include "os2.h"
+#include "limits.h"
+
+#include "process.h"
+
+#if defined(PYCC_GCC)
+#include <sys/builtin.h>
+#include <sys/fmutex.h>
+#else
+long PyThread_get_thread_ident(void);
+#endif
+
+/* default thread stack size of 64kB */
+#if !defined(THREAD_STACK_SIZE)
+#define THREAD_STACK_SIZE 0x10000
+#endif
+
+#define OS2_STACKSIZE(x) (x ? x : THREAD_STACK_SIZE)
+
+/*
+ * Initialization of the C package, should not be needed.
+ */
+static void
+PyThread__init_thread(void)
+{
+}
+
+/*
+ * Thread support.
+ */
+long
+PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ int thread_id;
+
+ thread_id = _beginthread(func,
+ NULL,
+ OS2_STACKSIZE(_pythread_stacksize),
+ arg);
+
+ if (thread_id == -1) {
+ dprintf(("_beginthread failed. return %ld\n", errno));
+ }
+
+ return thread_id;
+}
+
+long
+PyThread_get_thread_ident(void)
+{
+#if !defined(PYCC_GCC)
+ PPIB pib;
+ PTIB tib;
+#endif
+
+ if (!initialized)
+ PyThread_init_thread();
+
+#if defined(PYCC_GCC)
+ return _gettid();
+#else
+ DosGetInfoBlocks(&tib, &pib);
+ return tib->tib_ptib2->tib2_ultid;
+#endif
+}
+
+void
+PyThread_exit_thread(void)
+{
+ dprintf(("%ld: PyThread_exit_thread called\n",
+ PyThread_get_thread_ident()));
+ if (!initialized)
+ exit(0);
+ _endthread();
+}
+
+/*
+ * Lock support. This is implemented with an event semaphore and critical
+ * sections to make it behave more like a posix mutex than its OS/2
+ * counterparts.
+ */
+
+typedef struct os2_lock_t {
+ int is_set;
+ HEV changed;
+} *type_os2_lock;
+
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+#if defined(PYCC_GCC)
+ _fmutex *sem = malloc(sizeof(_fmutex));
+ if (!initialized)
+ PyThread_init_thread();
+ dprintf(("%ld: PyThread_allocate_lock() -> %lx\n",
+ PyThread_get_thread_ident(),
+ (long)sem));
+ if (_fmutex_create(sem, 0)) {
+ free(sem);
+ sem = NULL;
+ }
+ return (PyThread_type_lock)sem;
+#else
+ APIRET rc;
+ type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t));
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock->is_set = 0;
+
+ DosCreateEventSem(NULL, &lock->changed, 0, 0);
+
+ dprintf(("%ld: PyThread_allocate_lock() -> %p\n",
+ PyThread_get_thread_ident(),
+ lock->changed));
+
+ return (PyThread_type_lock)lock;
+#endif
+}
+
+void
+PyThread_free_lock(PyThread_type_lock aLock)
+{
+#if !defined(PYCC_GCC)
+ type_os2_lock lock = (type_os2_lock)aLock;
+#endif
+
+ dprintf(("%ld: PyThread_free_lock(%p) called\n",
+ PyThread_get_thread_ident(),aLock));
+
+#if defined(PYCC_GCC)
+ if (aLock) {
+ _fmutex_close((_fmutex *)aLock);
+ free((_fmutex *)aLock);
+ }
+#else
+ DosCloseEventSem(lock->changed);
+ free(aLock);
+#endif
+}
+
+/*
+ * Return 1 on success if the lock was acquired
+ *
+ * and 0 if the lock was not acquired.
+ */
+int
+PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
+{
+#if !defined(PYCC_GCC)
+ int done = 0;
+ ULONG count;
+ PID pid = 0;
+ TID tid = 0;
+ type_os2_lock lock = (type_os2_lock)aLock;
+#endif
+
+ dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n",
+ PyThread_get_thread_ident(),
+ aLock,
+ waitflag));
+
+#if defined(PYCC_GCC)
+ /* always successful if the lock doesn't exist */
+ if (aLock &&
+ _fmutex_request((_fmutex *)aLock, waitflag ? 0 : _FMR_NOWAIT))
+ return 0;
+#else
+ while (!done) {
+ /* if the lock is currently set, we have to wait for
+ * the state to change
+ */
+ if (lock->is_set) {
+ if (!waitflag)
+ return 0;
+ DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT);
+ }
+
+ /* enter a critical section and try to get the semaphore. If
+ * it is still locked, we will try again.
+ */
+ if (DosEnterCritSec())
+ return 0;
+
+ if (!lock->is_set) {
+ lock->is_set = 1;
+ DosResetEventSem(lock->changed, &count);
+ done = 1;
+ }
+
+ DosExitCritSec();
+ }
+#endif
+
+ return 1;
+}
+
+void
+PyThread_release_lock(PyThread_type_lock aLock)
+{
+#if !defined(PYCC_GCC)
+ type_os2_lock lock = (type_os2_lock)aLock;
+#endif
+
+ dprintf(("%ld: PyThread_release_lock(%p) called\n",
+ PyThread_get_thread_ident(),
+ aLock));
+
+#if defined(PYCC_GCC)
+ if (aLock)
+ _fmutex_release((_fmutex *)aLock);
+#else
+ if (!lock->is_set) {
+ dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n",
+ PyThread_get_thread_ident(),
+ aLock,
+ GetLastError()));
+ return;
+ }
+
+ if (DosEnterCritSec()) {
+ dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n",
+ PyThread_get_thread_ident(),
+ aLock,
+ GetLastError()));
+ return;
+ }
+
+ lock->is_set = 0;
+ DosPostEventSem(lock->changed);
+
+ DosExitCritSec();
+#endif
+}
+
+/* minimum/maximum thread stack sizes supported */
+#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
+#define THREAD_MAX_STACKSIZE 0x2000000 /* 32MB */
+
+/* set the thread stack size.
+ * Return 0 if size is valid, -1 otherwise.
+ */
+static int
+_pythread_os2_set_stacksize(size_t size)
+{
+ /* set to default */
+ if (size == 0) {
+ _pythread_stacksize = 0;
+ return 0;
+ }
+
+ /* valid range? */
+ if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
+ _pythread_stacksize = size;
+ return 0;
+ }
+
+ return -1;
+}
+
+#define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x)
diff --git a/contrib/tools/python/src/Python/thread_pth.h b/contrib/tools/python/src/Python/thread_pth.h
new file mode 100644
index 0000000000..82a00e72ba
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_pth.h
@@ -0,0 +1,178 @@
+
+/* GNU pth threads interface
+ http://www.gnu.org/software/pth
+ 2000-05-03 Andy Dustman <andy@dustman.net>
+
+ Adapted from Posix threads interface
+ 12 May 1997 -- david arnold <davida@pobox.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pth.h>
+
+/* A pth mutex isn't sufficient to model the Python lock type
+ * because pth mutexes can be acquired multiple times by the
+ * same thread.
+ *
+ * The pth_lock struct implements a Python lock as a "locked?" bit
+ * and a <condition, mutex> pair. In general, if the bit can be acquired
+ * instantly, it is, else the pair is used to block the thread until the
+ * bit is cleared.
+ */
+
+typedef struct {
+ char locked; /* 0=unlocked, 1=locked */
+ /* a <cond, mutex> pair to handle an acquire of a locked lock */
+ pth_cond_t lock_released;
+ pth_mutex_t mut;
+} pth_lock;
+
+#define CHECK_STATUS(name) if (status == -1) { printf("%d ", status); perror(name); error = 1; }
+
+pth_attr_t PyThread_attr;
+
+/*
+ * Initialization.
+ */
+
+static void PyThread__init_thread(void)
+{
+ pth_init();
+ PyThread_attr = pth_attr_new();
+ pth_attr_set(PyThread_attr, PTH_ATTR_STACK_SIZE, 1<<18);
+ pth_attr_set(PyThread_attr, PTH_ATTR_JOINABLE, FALSE);
+}
+
+/*
+ * Thread support.
+ */
+
+
+long PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ pth_t th;
+ dprintf(("PyThread_start_new_thread called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ th = pth_spawn(PyThread_attr,
+ (void* (*)(void *))func,
+ (void *)arg
+ );
+
+ return th;
+}
+
+long PyThread_get_thread_ident(void)
+{
+ volatile pth_t threadid;
+ if (!initialized)
+ PyThread_init_thread();
+ /* Jump through some hoops for Alpha OSF/1 */
+ threadid = pth_self();
+ return (long) *(long *) &threadid;
+}
+
+void PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+ if (!initialized) {
+ exit(0);
+ }
+}
+
+/*
+ * Lock support.
+ */
+PyThread_type_lock PyThread_allocate_lock(void)
+{
+ pth_lock *lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock = (pth_lock *) malloc(sizeof(pth_lock));
+ memset((void *)lock, '\0', sizeof(pth_lock));
+ if (lock) {
+ lock->locked = 0;
+ status = pth_mutex_init(&lock->mut);
+ CHECK_STATUS("pth_mutex_init");
+ status = pth_cond_init(&lock->lock_released);
+ CHECK_STATUS("pth_cond_init");
+ if (error) {
+ free((void *)lock);
+ lock = NULL;
+ }
+ }
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void PyThread_free_lock(PyThread_type_lock lock)
+{
+ pth_lock *thelock = (pth_lock *)lock;
+
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+
+ free((void *)thelock);
+}
+
+int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success;
+ pth_lock *thelock = (pth_lock *)lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+
+ status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL);
+ CHECK_STATUS("pth_mutex_acquire[1]");
+ success = thelock->locked == 0;
+ if (success) thelock->locked = 1;
+ status = pth_mutex_release( &thelock->mut );
+ CHECK_STATUS("pth_mutex_release[1]");
+
+ if ( !success && waitflag ) {
+ /* continue trying until we get the lock */
+
+ /* mut must be locked by me -- part of the condition
+ * protocol */
+ status = pth_mutex_acquire( &thelock->mut, !waitflag, NULL );
+ CHECK_STATUS("pth_mutex_acquire[2]");
+ while ( thelock->locked ) {
+ status = pth_cond_await(&thelock->lock_released,
+ &thelock->mut, NULL);
+ CHECK_STATUS("pth_cond_await");
+ }
+ thelock->locked = 1;
+ status = pth_mutex_release( &thelock->mut );
+ CHECK_STATUS("pth_mutex_release[2]");
+ success = 1;
+ }
+ if (error) success = 0;
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void PyThread_release_lock(PyThread_type_lock lock)
+{
+ pth_lock *thelock = (pth_lock *)lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+
+ status = pth_mutex_acquire( &thelock->mut, 0, NULL );
+ CHECK_STATUS("pth_mutex_acquire[3]");
+
+ thelock->locked = 0;
+
+ status = pth_mutex_release( &thelock->mut );
+ CHECK_STATUS("pth_mutex_release[3]");
+
+ /* wake up someone (anyone, if any) waiting on the lock */
+ status = pth_cond_notify( &thelock->lock_released, 0 );
+ CHECK_STATUS("pth_cond_notify");
+}
diff --git a/contrib/tools/python/src/Python/thread_pthread.h b/contrib/tools/python/src/Python/thread_pthread.h
new file mode 100644
index 0000000000..6d4b3b389f
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_pthread.h
@@ -0,0 +1,553 @@
+
+/* Posix threads interface */
+
+#include <stdlib.h>
+#include <string.h>
+#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
+#define destructor xxdestructor
+#endif
+#include <pthread.h>
+#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
+#undef destructor
+#endif
+#include <signal.h>
+
+/* The POSIX spec requires that use of pthread_attr_setstacksize
+ be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+#ifndef THREAD_STACK_SIZE
+#define THREAD_STACK_SIZE 0 /* use default stack size */
+#endif
+
+#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
+ /* The default stack size for new threads on OSX is small enough that
+ * we'll get hard crashes instead of 'maximum recursion depth exceeded'
+ * exceptions.
+ *
+ * The default stack size below is the minimal stack size where a
+ * simple recursive function doesn't cause a hard crash.
+ */
+#undef THREAD_STACK_SIZE
+#define THREAD_STACK_SIZE 0x400000
+#endif
+/* for safety, ensure a viable minimum stacksize */
+#define THREAD_STACK_MIN 0x8000 /* 32kB */
+#else /* !_POSIX_THREAD_ATTR_STACKSIZE */
+#ifdef THREAD_STACK_SIZE
+#error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"
+#endif
+#endif
+
+/* The POSIX spec says that implementations supporting the sem_*
+ family of functions must indicate this by defining
+ _POSIX_SEMAPHORES. */
+#ifdef _POSIX_SEMAPHORES
+/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
+ we need to add 0 to make it work there as well. */
+#if (_POSIX_SEMAPHORES+0) == -1
+#define HAVE_BROKEN_POSIX_SEMAPHORES
+#else
+#include <semaphore.h>
+#include <errno.h>
+#endif
+#endif
+
+/* Before FreeBSD 5.4, system scope threads was very limited resource
+ in default setting. So the process scope is preferred to get
+ enough number of threads to work. */
+#ifdef __FreeBSD__
+#include <osreldate.h>
+#if __FreeBSD_version >= 500000 && __FreeBSD_version < 504101
+#undef PTHREAD_SYSTEM_SCHED_SUPPORTED
+#endif
+#endif
+
+#if !defined(pthread_attr_default)
+# define pthread_attr_default ((pthread_attr_t *)NULL)
+#endif
+#if !defined(pthread_mutexattr_default)
+# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
+#endif
+#if !defined(pthread_condattr_default)
+# define pthread_condattr_default ((pthread_condattr_t *)NULL)
+#endif
+
+
+/* Whether or not to use semaphores directly rather than emulating them with
+ * mutexes and condition variables:
+ */
+#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES)
+# define USE_SEMAPHORES
+#else
+# undef USE_SEMAPHORES
+#endif
+
+
+/* On platforms that don't use standard POSIX threads pthread_sigmask()
+ * isn't present. DEC threads uses sigprocmask() instead as do most
+ * other UNIX International compliant systems that don't have the full
+ * pthread implementation.
+ */
+#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
+# define SET_THREAD_SIGMASK pthread_sigmask
+#else
+# define SET_THREAD_SIGMASK sigprocmask
+#endif
+
+
+/* A pthread mutex isn't sufficient to model the Python lock type
+ * because, according to Draft 5 of the docs (P1003.4a/D5), both of the
+ * following are undefined:
+ * -> a thread tries to lock a mutex it already has locked
+ * -> a thread tries to unlock a mutex locked by a different thread
+ * pthread mutexes are designed for serializing threads over short pieces
+ * of code anyway, so wouldn't be an appropriate implementation of
+ * Python's locks regardless.
+ *
+ * The pthread_lock struct implements a Python lock as a "locked?" bit
+ * and a <condition, mutex> pair. In general, if the bit can be acquired
+ * instantly, it is, else the pair is used to block the thread until the
+ * bit is cleared. 9 May 1994 tim@ksr.com
+ */
+
+typedef struct {
+ char locked; /* 0=unlocked, 1=locked */
+ /* a <cond, mutex> pair to handle an acquire of a locked lock */
+ pthread_cond_t lock_released;
+ pthread_mutex_t mut;
+} pthread_lock;
+
+#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
+
+/*
+ * Initialization.
+ */
+
+#ifdef _HAVE_BSDI
+static
+void _noop(void)
+{
+}
+
+static void
+PyThread__init_thread(void)
+{
+ /* DO AN INIT BY STARTING THE THREAD */
+ static int dummy = 0;
+ pthread_t thread1;
+ pthread_create(&thread1, NULL, (void *) _noop, &dummy);
+ pthread_join(thread1, NULL);
+}
+
+#else /* !_HAVE_BSDI */
+
+static void
+PyThread__init_thread(void)
+{
+#if defined(_AIX) && defined(__GNUC__)
+ extern void pthread_init(void);
+ pthread_init();
+#endif
+}
+
+#endif /* !_HAVE_BSDI */
+
+/*
+ * Thread support.
+ */
+
+/* bpo-33015: pythread_callback struct and pythread_wrapper() cast
+ "void func(void *)" to "void* func(void *)": always return NULL.
+
+ PyThread_start_new_thread() uses "void func(void *)" type, whereas
+ pthread_create() requires a void* return value. */
+typedef struct {
+ void (*func) (void *);
+ void *arg;
+} pythread_callback;
+
+static void *
+pythread_wrapper(void *arg)
+{
+ /* copy func and func_arg and free the temporary structure */
+ pythread_callback *callback = arg;
+ void (*func)(void *) = callback->func;
+ void *func_arg = callback->arg;
+ free(arg);
+
+ func(func_arg);
+ return NULL;
+}
+
+long
+PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+ pthread_t th;
+ int status;
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+ pthread_attr_t attrs;
+#endif
+#if defined(THREAD_STACK_SIZE)
+ size_t tss;
+#endif
+
+ dprintf(("PyThread_start_new_thread called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+ if (pthread_attr_init(&attrs) != 0)
+ return -1;
+#endif
+#if defined(THREAD_STACK_SIZE)
+ tss = (_pythread_stacksize != 0) ? _pythread_stacksize
+ : THREAD_STACK_SIZE;
+ if (tss != 0) {
+ if (pthread_attr_setstacksize(&attrs, tss) != 0) {
+ pthread_attr_destroy(&attrs);
+ return -1;
+ }
+ }
+#endif
+#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+ pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
+#endif
+
+ pythread_callback *callback = malloc(sizeof(pythread_callback));
+
+ if (callback == NULL) {
+ return -1;
+ }
+
+ callback->func = func;
+ callback->arg = arg;
+
+ status = pthread_create(&th,
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+ &attrs,
+#else
+ (pthread_attr_t*)NULL,
+#endif
+ pythread_wrapper, callback);
+
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+ pthread_attr_destroy(&attrs);
+#endif
+
+ if (status != 0) {
+ free(callback);
+ return -1;
+ }
+
+ pthread_detach(th);
+
+#if SIZEOF_PTHREAD_T <= SIZEOF_LONG
+ return (long) th;
+#else
+ return (long) *(long *) &th;
+#endif
+}
+
+/* XXX This implementation is considered (to quote Tim Peters) "inherently
+ hosed" because:
+ - It does not guarantee the promise that a non-zero integer is returned.
+ - The cast to long is inherently unsafe.
+ - It is not clear that the 'volatile' (for AIX?) and ugly casting in the
+ latter return statement (for Alpha OSF/1) are any longer necessary.
+*/
+long
+PyThread_get_thread_ident(void)
+{
+ volatile pthread_t threadid;
+ if (!initialized)
+ PyThread_init_thread();
+ /* Jump through some hoops for Alpha OSF/1 */
+ threadid = pthread_self();
+#if SIZEOF_PTHREAD_T <= SIZEOF_LONG
+ return (long) threadid;
+#else
+ return (long) *(long *) &threadid;
+#endif
+}
+
+void
+PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+ if (!initialized) {
+ exit(0);
+ }
+}
+
+#ifdef USE_SEMAPHORES
+
+/*
+ * Lock support.
+ */
+
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+ sem_t *lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock = (sem_t *)malloc(sizeof(sem_t));
+
+ if (lock) {
+ status = sem_init(lock,0,1);
+ CHECK_STATUS("sem_init");
+
+ if (error) {
+ free((void *)lock);
+ lock = NULL;
+ }
+ }
+
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock)lock;
+}
+
+void
+PyThread_free_lock(PyThread_type_lock lock)
+{
+ sem_t *thelock = (sem_t *)lock;
+ int status, error = 0;
+
+ (void) error; /* silence unused-but-set-variable warning */
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+
+ if (!thelock)
+ return;
+
+ status = sem_destroy(thelock);
+ CHECK_STATUS("sem_destroy");
+
+ free((void *)thelock);
+}
+
+/*
+ * As of February 2002, Cygwin thread implementations mistakenly report error
+ * codes in the return value of the sem_ calls (like the pthread_ functions).
+ * Correct implementations return -1 and put the code in errno. This supports
+ * either.
+ */
+static int
+fix_status(int status)
+{
+ return (status == -1) ? errno : status;
+}
+
+int
+PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success;
+ sem_t *thelock = (sem_t *)lock;
+ int status, error = 0;
+
+ (void) error; /* silence unused-but-set-variable warning */
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+
+ do {
+ if (waitflag)
+ status = fix_status(sem_wait(thelock));
+ else
+ status = fix_status(sem_trywait(thelock));
+ } while (status == EINTR); /* Retry if interrupted by a signal */
+
+ if (waitflag) {
+ CHECK_STATUS("sem_wait");
+ } else if (status != EAGAIN) {
+ CHECK_STATUS("sem_trywait");
+ }
+
+ success = (status == 0) ? 1 : 0;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void
+PyThread_release_lock(PyThread_type_lock lock)
+{
+ sem_t *thelock = (sem_t *)lock;
+ int status, error = 0;
+
+ (void) error; /* silence unused-but-set-variable warning */
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+
+ status = sem_post(thelock);
+ CHECK_STATUS("sem_post");
+}
+
+#else /* USE_SEMAPHORES */
+
+/*
+ * Lock support.
+ */
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+ pthread_lock *lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ lock = (pthread_lock *) malloc(sizeof(pthread_lock));
+ if (lock) {
+ memset((void *)lock, '\0', sizeof(pthread_lock));
+ lock->locked = 0;
+
+ status = pthread_mutex_init(&lock->mut,
+ pthread_mutexattr_default);
+ CHECK_STATUS("pthread_mutex_init");
+
+ status = pthread_cond_init(&lock->lock_released,
+ pthread_condattr_default);
+ CHECK_STATUS("pthread_cond_init");
+
+ if (error) {
+ free((void *)lock);
+ lock = 0;
+ }
+ }
+
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void
+PyThread_free_lock(PyThread_type_lock lock)
+{
+ pthread_lock *thelock = (pthread_lock *)lock;
+ int status, error = 0;
+
+ (void) error; /* silence unused-but-set-variable warning */
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+
+ status = pthread_mutex_destroy( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_destroy");
+
+ status = pthread_cond_destroy( &thelock->lock_released );
+ CHECK_STATUS("pthread_cond_destroy");
+
+ free((void *)thelock);
+}
+
+int
+PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success = 0;
+ pthread_lock *thelock = (pthread_lock *)lock;
+ int status, error = 0;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+
+ if (waitflag) {
+ status = pthread_mutex_lock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_lock[1]");
+ }
+ else {
+ status = pthread_mutex_trylock( &thelock->mut );
+ if (status != EBUSY)
+ CHECK_STATUS("pthread_mutex_trylock[1]");
+ }
+ if (status == 0) {
+ success = thelock->locked == 0;
+
+ if ( !success && waitflag ) {
+ /* continue trying until we get the lock */
+
+ /* mut must be locked by me -- part of the condition
+ * protocol */
+ while ( thelock->locked ) {
+ status = pthread_cond_wait(&thelock->lock_released,
+ &thelock->mut);
+ CHECK_STATUS("pthread_cond_wait");
+ }
+ success = 1;
+ }
+
+ if (success) thelock->locked = 1;
+ status = pthread_mutex_unlock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_unlock[1]");
+ }
+
+ if (error) success = 0;
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void
+PyThread_release_lock(PyThread_type_lock lock)
+{
+ pthread_lock *thelock = (pthread_lock *)lock;
+ int status, error = 0;
+
+ (void) error; /* silence unused-but-set-variable warning */
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+
+ status = pthread_mutex_lock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_lock[3]");
+
+ thelock->locked = 0;
+
+ status = pthread_mutex_unlock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_unlock[3]");
+
+ /* wake up someone (anyone, if any) waiting on the lock */
+ status = pthread_cond_signal( &thelock->lock_released );
+ CHECK_STATUS("pthread_cond_signal");
+}
+
+#endif /* USE_SEMAPHORES */
+
+/* set the thread stack size.
+ * Return 0 if size is valid, -1 if size is invalid,
+ * -2 if setting stack size is not supported.
+ */
+static int
+_pythread_pthread_set_stacksize(size_t size)
+{
+#if defined(THREAD_STACK_SIZE)
+ pthread_attr_t attrs;
+ size_t tss_min;
+ int rc = 0;
+#endif
+
+ /* set to default */
+ if (size == 0) {
+ _pythread_stacksize = 0;
+ return 0;
+ }
+
+#if defined(THREAD_STACK_SIZE)
+#if defined(PTHREAD_STACK_MIN)
+ tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN
+ : THREAD_STACK_MIN;
+#else
+ tss_min = THREAD_STACK_MIN;
+#endif
+ if (size >= tss_min) {
+ /* validate stack size by setting thread attribute */
+ if (pthread_attr_init(&attrs) == 0) {
+ rc = pthread_attr_setstacksize(&attrs, size);
+ pthread_attr_destroy(&attrs);
+ if (rc == 0) {
+ _pythread_stacksize = size;
+ return 0;
+ }
+ }
+ }
+ return -1;
+#else
+ return -2;
+#endif
+}
+
+#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)
diff --git a/contrib/tools/python/src/Python/thread_sgi.h b/contrib/tools/python/src/Python/thread_sgi.h
new file mode 100644
index 0000000000..771ab2cc60
--- /dev/null
+++ b/contrib/tools/python/src/Python/thread_sgi.h
@@ -0,0 +1,259 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <ulocks.h>
+#include <errno.h>
+
+#define HDR_SIZE 2680 /* sizeof(ushdr_t) */
+#define MAXPROC 100 /* max # of threads that can be started */
+
+static usptr_t *shared_arena;
+static ulock_t count_lock; /* protection for some variables */
+static ulock_t wait_lock; /* lock used to wait for other threads */
+static int waiting_for_threads; /* protected by count_lock */
+static int nthreads; /* protected by count_lock */
+static int exit_status;
+static int exiting; /* we're already exiting (for maybe_exit) */
+static pid_t my_pid; /* PID of main thread */
+static struct pidlist {
+ pid_t parent;
+ pid_t child;
+} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
+static int maxpidindex; /* # of PIDs in pidlist */
+/*
+ * Initialization.
+ */
+static void PyThread__init_thread(void)
+{
+#ifdef USE_DL
+ long addr, size;
+#endif /* USE_DL */
+
+
+#ifdef USE_DL
+ if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
+ perror("usconfig - CONF_INITSIZE (check)");
+ if (usconfig(CONF_INITSIZE, size) < 0)
+ perror("usconfig - CONF_INITSIZE (reset)");
+ addr = (long) dl_getrange(size + HDR_SIZE);
+ dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
+ errno = 0;
+ if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
+ perror("usconfig - CONF_ATTACHADDR (set)");
+#endif /* USE_DL */
+ if (usconfig(CONF_INITUSERS, 16) < 0)
+ perror("usconfig - CONF_INITUSERS");
+ my_pid = getpid(); /* so that we know which is the main thread */
+ if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
+ perror("usconfig - CONF_ARENATYPE");
+ usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
+#ifdef Py_DEBUG
+ if (thread_debug & 4)
+ usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
+ else if (thread_debug & 2)
+ usconfig(CONF_LOCKTYPE, US_DEBUG);
+#endif /* Py_DEBUG */
+ if ((shared_arena = usinit(tmpnam(0))) == 0)
+ perror("usinit");
+#ifdef USE_DL
+ if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
+ perror("usconfig - CONF_ATTACHADDR (reset)");
+#endif /* USE_DL */
+ if ((count_lock = usnewlock(shared_arena)) == NULL)
+ perror("usnewlock (count_lock)");
+ (void) usinitlock(count_lock);
+ if ((wait_lock = usnewlock(shared_arena)) == NULL)
+ perror("usnewlock (wait_lock)");
+ dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
+}
+
+/*
+ * Thread support.
+ */
+
+static void clean_threads(void)
+{
+ int i, j;
+ pid_t mypid, pid;
+
+ /* clean up any exited threads */
+ mypid = getpid();
+ i = 0;
+ while (i < maxpidindex) {
+ if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
+ pid = waitpid(pid, 0, WNOHANG);
+ if (pid > 0) {
+ /* a thread has exited */
+ pidlist[i] = pidlist[--maxpidindex];
+ /* remove references to children of dead proc */
+ for (j = 0; j < maxpidindex; j++)
+ if (pidlist[j].parent == pid)
+ pidlist[j].child = -1;
+ continue; /* don't increment i */
+ }
+ }
+ i++;
+ }
+ /* clean up the list */
+ i = 0;
+ while (i < maxpidindex) {
+ if (pidlist[i].child == -1) {
+ pidlist[i] = pidlist[--maxpidindex];
+ continue; /* don't increment i */
+ }
+ i++;
+ }
+}
+
+long PyThread_start_new_thread(void (*func)(void *), void *arg)
+{
+#ifdef USE_DL
+ long addr, size;
+ static int local_initialized = 0;
+#endif /* USE_DL */
+ int success = 0; /* init not needed when SOLARIS_THREADS and */
+ /* C_THREADS implemented properly */
+
+ dprintf(("PyThread_start_new_thread called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+ switch (ussetlock(count_lock)) {
+ case 0: return 0;
+ case -1: perror("ussetlock (count_lock)");
+ }
+ if (maxpidindex >= MAXPROC)
+ success = -1;
+ else {
+#ifdef USE_DL
+ if (!local_initialized) {
+ if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
+ perror("usconfig - CONF_INITSIZE (check)");
+ if (usconfig(CONF_INITSIZE, size) < 0)
+ perror("usconfig - CONF_INITSIZE (reset)");
+ addr = (long) dl_getrange(size + HDR_SIZE);
+ dprintf(("trying to use addr %p-%p for sproc\n",
+ addr, addr+size));
+ errno = 0;
+ if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
+ errno != 0)
+ perror("usconfig - CONF_ATTACHADDR (set)");
+ }
+#endif /* USE_DL */
+ clean_threads();
+ if ((success = sproc(func, PR_SALL, arg)) < 0)
+ perror("sproc");
+#ifdef USE_DL
+ if (!local_initialized) {
+ if (usconfig(CONF_ATTACHADDR, addr) < 0)
+ /* reset address */
+ perror("usconfig - CONF_ATTACHADDR (reset)");
+ local_initialized = 1;
+ }
+#endif /* USE_DL */
+ if (success >= 0) {
+ nthreads++;
+ pidlist[maxpidindex].parent = getpid();
+ pidlist[maxpidindex++].child = success;
+ dprintf(("pidlist[%d] = %d\n",
+ maxpidindex-1, success));
+ }
+ }
+ if (usunsetlock(count_lock) < 0)
+ perror("usunsetlock (count_lock)");
+ return success;
+}
+
+long PyThread_get_thread_ident(void)
+{
+ return getpid();
+}
+
+void PyThread_exit_thread(void)
+{
+ dprintf(("PyThread_exit_thread called\n"));
+ if (!initialized)
+ exit(0);
+ if (ussetlock(count_lock) < 0)
+ perror("ussetlock (count_lock)");
+ nthreads--;
+ if (getpid() == my_pid) {
+ /* main thread; wait for other threads to exit */
+ exiting = 1;
+ waiting_for_threads = 1;
+ if (ussetlock(wait_lock) < 0)
+ perror("ussetlock (wait_lock)");
+ for (;;) {
+ if (nthreads < 0) {
+ dprintf(("really exit (%d)\n", exit_status));
+ exit(exit_status);
+ }
+ if (usunsetlock(count_lock) < 0)
+ perror("usunsetlock (count_lock)");
+ dprintf(("waiting for other threads (%d)\n", nthreads));
+ if (ussetlock(wait_lock) < 0)
+ perror("ussetlock (wait_lock)");
+ if (ussetlock(count_lock) < 0)
+ perror("ussetlock (count_lock)");
+ }
+ }
+ /* not the main thread */
+ if (waiting_for_threads) {
+ dprintf(("main thread is waiting\n"));
+ if (usunsetlock(wait_lock) < 0)
+ perror("usunsetlock (wait_lock)");
+ }
+ if (usunsetlock(count_lock) < 0)
+ perror("usunsetlock (count_lock)");
+ _exit(0);
+}
+
+/*
+ * Lock support.
+ */
+PyThread_type_lock PyThread_allocate_lock(void)
+{
+ ulock_t lock;
+
+ dprintf(("PyThread_allocate_lock called\n"));
+ if (!initialized)
+ PyThread_init_thread();
+
+ if ((lock = usnewlock(shared_arena)) == NULL)
+ perror("usnewlock");
+ (void) usinitlock(lock);
+ dprintf(("PyThread_allocate_lock() -> %p\n", lock));
+ return (PyThread_type_lock) lock;
+}
+
+void PyThread_free_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_free_lock(%p) called\n", lock));
+ usfreelock((ulock_t) lock, shared_arena);
+}
+
+int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+ int success;
+
+ dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
+ errno = 0; /* clear it just in case */
+ if (waitflag)
+ success = ussetlock((ulock_t) lock);
+ else
+ success = uscsetlock((ulock_t) lock, 1); /* Try it once */
+ if (success < 0)
+ perror(waitflag ? "ussetlock" : "uscsetlock");
+ dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
+ return success;
+}
+
+void PyThread_release_lock(PyThread_type_lock lock)
+{
+ dprintf(("PyThread_release_lock(%p) called\n", lock));
+ if (usunsetlock((ulock_t) lock) < 0)
+ perror("usunsetlock");
+}
diff --git a/contrib/tools/python/src/Python/traceback.c b/contrib/tools/python/src/Python/traceback.c
new file mode 100644
index 0000000000..fd5309ae3f
--- /dev/null
+++ b/contrib/tools/python/src/Python/traceback.c
@@ -0,0 +1,279 @@
+
+/* Traceback implementation */
+
+#include "Python.h"
+
+#include "code.h"
+#include "frameobject.h"
+#include "structmember.h"
+#include "osdefs.h"
+#include "traceback.h"
+
+#define OFF(x) offsetof(PyTracebackObject, x)
+
+static PyMemberDef tb_memberlist[] = {
+ {"tb_next", T_OBJECT, OFF(tb_next), READONLY},
+ {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
+ {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
+ {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
+ {NULL} /* Sentinel */
+};
+
+static void
+tb_dealloc(PyTracebackObject *tb)
+{
+ PyObject_GC_UnTrack(tb);
+ Py_TRASHCAN_SAFE_BEGIN(tb)
+ Py_XDECREF(tb->tb_next);
+ Py_XDECREF(tb->tb_frame);
+ PyObject_GC_Del(tb);
+ Py_TRASHCAN_SAFE_END(tb)
+}
+
+static int
+tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
+{
+ Py_VISIT(tb->tb_next);
+ Py_VISIT(tb->tb_frame);
+ return 0;
+}
+
+static void
+tb_clear(PyTracebackObject *tb)
+{
+ Py_CLEAR(tb->tb_next);
+ Py_CLEAR(tb->tb_frame);
+}
+
+PyTypeObject PyTraceBack_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "traceback",
+ sizeof(PyTracebackObject),
+ 0,
+ (destructor)tb_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)tb_traverse, /* tp_traverse */
+ (inquiry)tb_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ tb_memberlist, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+};
+
+static PyTracebackObject *
+newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
+{
+ PyTracebackObject *tb;
+ if ((next != NULL && !PyTraceBack_Check(next)) ||
+ frame == NULL || !PyFrame_Check(frame)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
+ if (tb != NULL) {
+ Py_XINCREF(next);
+ tb->tb_next = next;
+ Py_XINCREF(frame);
+ tb->tb_frame = frame;
+ tb->tb_lasti = frame->f_lasti;
+ tb->tb_lineno = PyFrame_GetLineNumber(frame);
+ PyObject_GC_Track(tb);
+ }
+ return tb;
+}
+
+int
+PyTraceBack_Here(PyFrameObject *frame)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
+ PyTracebackObject *tb = newtracebackobject(oldtb, frame);
+ if (tb == NULL)
+ return -1;
+ tstate->curexc_traceback = (PyObject *)tb;
+ Py_XDECREF(oldtb);
+ return 0;
+}
+
+int
+_Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno, int indent)
+{
+ int err = 0;
+ FILE *xfp = NULL;
+ char linebuf[2000];
+ int i;
+ char namebuf[MAXPATHLEN+1];
+
+ if (filename == NULL)
+ return -1;
+ /* This is needed by Emacs' compile command */
+#define FMT " File \"%.500s\", line %d, in %.500s\n"
+ xfp = fopen(filename, "r" PY_STDIOTEXTMODE);
+ if (xfp == NULL) {
+ /* Search tail of filename in sys.path before giving up */
+ PyObject *path;
+ const char *tail = strrchr(filename, SEP);
+ if (tail == NULL)
+ tail = filename;
+ else
+ tail++;
+ path = PySys_GetObject("path");
+ if (path != NULL && PyList_Check(path)) {
+ Py_ssize_t _npath = PyList_Size(path);
+ int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int);
+ size_t taillen = strlen(tail);
+ for (i = 0; i < npath; i++) {
+ PyObject *v = PyList_GetItem(path, i);
+ if (v == NULL) {
+ PyErr_Clear();
+ break;
+ }
+ if (PyString_Check(v)) {
+ size_t len;
+ len = PyString_GET_SIZE(v);
+ if (len + 1 + taillen >= MAXPATHLEN)
+ continue; /* Too long */
+ strcpy(namebuf, PyString_AsString(v));
+ if (strlen(namebuf) != len)
+ continue; /* v contains '\0' */
+ if (len > 0 && namebuf[len-1] != SEP)
+ namebuf[len++] = SEP;
+ strcpy(namebuf+len, tail);
+ xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE);
+ if (xfp != NULL) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (xfp == NULL)
+ return err;
+
+ for (i = 0; i < lineno; i++) {
+ char* pLastChar = &linebuf[sizeof(linebuf)-2];
+ do {
+ *pLastChar = '\0';
+ if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL)
+ break;
+ /* fgets read *something*; if it didn't get as
+ far as pLastChar, it must have found a newline
+ or hit the end of the file; if pLastChar is \n,
+ it obviously found a newline; else we haven't
+ yet seen a newline, so must continue */
+ } while (*pLastChar != '\0' && *pLastChar != '\n');
+ }
+ if (i == lineno) {
+ char buf[11];
+ char *p = linebuf;
+ while (*p == ' ' || *p == '\t' || *p == '\014')
+ p++;
+
+ /* Write some spaces before the line */
+ strcpy(buf, " ");
+ assert (strlen(buf) == 10);
+ while (indent > 0) {
+ if(indent < 10)
+ buf[indent] = '\0';
+ err = PyFile_WriteString(buf, f);
+ if (err != 0)
+ break;
+ indent -= 10;
+ }
+
+ if (err == 0)
+ err = PyFile_WriteString(p, f);
+ if (err == 0 && strchr(p, '\n') == NULL)
+ err = PyFile_WriteString("\n", f);
+ }
+ fclose(xfp);
+ return err;
+}
+
+static int
+tb_displayline(PyObject *f, const char *filename, int lineno, const char *name)
+{
+ int err = 0;
+ char linebuf[2000];
+
+ if (filename == NULL || name == NULL)
+ return -1;
+ /* This is needed by Emacs' compile command */
+#define FMT " File \"%.500s\", line %d, in %.500s\n"
+ PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);
+ err = PyFile_WriteString(linebuf, f);
+ if (err != 0)
+ return err;
+ return _Py_DisplaySourceLine(f, filename, lineno, 4);
+}
+
+static int
+tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
+{
+ int err = 0;
+ long depth = 0;
+ PyTracebackObject *tb1 = tb;
+ while (tb1 != NULL) {
+ depth++;
+ tb1 = tb1->tb_next;
+ }
+ while (tb != NULL && err == 0) {
+ if (depth <= limit) {
+ err = tb_displayline(f,
+ PyString_AsString(
+ tb->tb_frame->f_code->co_filename),
+ tb->tb_lineno,
+ PyString_AsString(tb->tb_frame->f_code->co_name));
+ }
+ depth--;
+ tb = tb->tb_next;
+ if (err == 0)
+ err = PyErr_CheckSignals();
+ }
+ return err;
+}
+
+int
+PyTraceBack_Print(PyObject *v, PyObject *f)
+{
+ int err;
+ PyObject *limitv;
+ long limit = 1000;
+ if (v == NULL)
+ return 0;
+ if (!PyTraceBack_Check(v)) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ limitv = PySys_GetObject("tracebacklimit");
+ if (limitv && PyInt_Check(limitv)) {
+ limit = PyInt_AsLong(limitv);
+ if (limit <= 0)
+ return 0;
+ }
+ err = PyFile_WriteString("Traceback (most recent call last):\n", f);
+ if (!err)
+ err = tb_printinternal((PyTracebackObject *)v, f, limit);
+ return err;
+}