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_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PyObject *global) { PyObject *name, *v, *local = NULL, *scope = NULL, *newbound = NULL; PyObject *newglobal = NULL, *newfree = NULL; int i, success = 0; Py_ssize_t pos = 0; local = PyDict_New(); if (!local) goto error; scope = PyDict_New(); if (!scope) goto error; newglobal = PyDict_New(); if (!newglobal) goto error; newfree = PyDict_New(); if (!newfree) goto error; newbound = PyDict_New(); if (!newbound) goto error; if (ste->ste_type == ClassBlock) { /* make a copy of globals before calling analyze_name(), because global statements in the class have no effect on nested functions. */ if (PyDict_Update(newglobal, global) < 0) goto error; if (bound) if (PyDict_Update(newbound, bound) < 0) goto error; } assert(PySTEntry_Check(ste)); assert(PyDict_Check(ste->ste_symbols)); 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 */ 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_block(entry, newbound, newfree, newglobal)) goto error; if (entry->ste_free || entry->ste_child_free) ste->ste_child_free = 1; } 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); if (!success) assert(PyErr_Occurred()); return success; }